Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
 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()
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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()
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
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()
Ejemplo n.º 8
0
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()
Ejemplo n.º 9
0
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")
Ejemplo n.º 10
0
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")
Ejemplo n.º 11
0
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()
Ejemplo n.º 12
0
class TestRun(object):
    def __init__(self, adb="adb", serial=None):
        self.test_results = {}
        self.test_results_file = None
        self.m = None
        self.gaia_apps = None
        self.screenshot_path = None
        self.logcat_path = None
        self.app_name = None
        self.attempt = None
        self.num_apps = None
        self.device = None
        self.serial = serial
        self.port = None
        self.run_log = logging.getLogger('marketplace-test')
        if self.serial:
            self.dm = DeviceManagerADB(adbPath=adb, deviceSerial=serial)
        else:
            self.dm = DeviceManagerADB(adbPath=adb)

    def reset_marionette(self):
        try:
            self.m.delete_session()
        except Exception:
            pass
        self.m = None
        self.get_marionette()

    def get_marionette(self):
        if not self.m:
            self.m = Marionette(port=self.port)
            self.m.start_session()
            self.device = GaiaDevice(self.m)
            self.device.add_device_manager(self.dm)
            self.gaia_apps = GaiaApps(self.m)
        else:
            tries = 5
            while tries > 0:
                try:
                    self.m.get_url()
                    break
                except MarionetteException as e:
                    if "Please start a session" in str(e):
                        time.sleep(5)
                        self.m = Marionette(port=self.port)
                        self.m.start_session()
                        self.device = GaiaDevice(self.m)
                        self.device.add_device_manager(self.dm)
                        self.gaia_apps = GaiaApps(self.m)
                        tries -= 1
                    else:
                        raise e
            else:
                self.run_log.error("Can't connect to marionette, rebooting")
                self.restart_device()
        return self.m

    def write_to_file(self, data):
        with open("%s.tmp" % self.test_results_file, "w") as f:
            f.write(data)
        shutil.copyfile("%s.tmp" % self.test_results_file,
                        self.test_results_file)

    def add_values(self, key, value):
        if self.serial:
            self.test_results["%s_%s" % (key, self.serial)] = value
        else:
            self.test_results["%s" % key] = value

    def add_result(self, passed=False, status=None, uninstalled_failure=False):
        values = {}
        if status:
            if not passed:
                values["status"] = "FAILED: %s" % status
            else:
                values["status"] = "PASS"
        if self.screenshot_path:
            values["screenshot"] = self.screenshot_path
        if self.logcat_path:
            values["logcat"] = self.logcat_path
        if uninstalled_failure:
            values["uninstalled_failure"] = uninstalled_failure
        entry = "%s_%s" % (self.app_name, self.attempt)
        self.test_results[entry] = values

    def launch_with_manifest(self, manifest):
        self.m.switch_to_frame()
        result = self.m.execute_async_script(
            "GaiaApps.launchWithManifestURL('%s')" % manifest,
            script_timeout=30000)
        if result == False:
            raise Exception("launch timed out")
        app = GaiaApp(frame=result.get('frame'),
                      src=result.get('src'),
                      name=result.get('name'),
                      origin=result.get('origin'))
        if app.frame_id is None:
            raise Exception("failed to launch; there is no app frame")
        self.m.switch_to_frame(app.frame_id)
        return app

    def uninstall_with_manifest(self, manifest):
        self.m.switch_to_frame()
        script = """
        GaiaApps.locateWithManifestURL('%s',
                                       null,
                                       function uninstall(app) {
                                       navigator.mozApps.mgmt.uninstall(app);
                                       marionetteScriptFinished(true);
                                       });
        """
        result = self.m.execute_async_script(script % manifest,
                                             script_timeout=60000)
        if result != True:
            self.add_result(status="Failed to uninstall app with url '%s'" %
                            manifest)
        return app

    def forward_port(self):
        # get unused port
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(('localhost', 0))
        addr, port = s.getsockname()
        s.close()

        dm_tries = 0
        self.run_log.info("using port %s" % port)
        while dm_tries < 20:
            if self.dm.forward("tcp:%d" % port, "tcp:2828") == 0:
                break
            dm_tries += 1
            time.sleep(3)
        else:
            return False
        self.port = port
        return True

    def restart_device(self, restart_tries=0):
        self.run_log.info("rebooting")
        # TODO restarting b2g doesn't seem to work... reboot then
        while restart_tries < 3:
            restart_tries += 1
            self.dm.reboot(wait=True)
            self.run_log.info("forwarding")
            if not self.forward_port():
                self.run_log.error("couldn't forward port in time, rebooting")
                continue
            self.m = Marionette(port=self.port)
            if not self.m.wait_for_port(180):
                self.run_log.error(
                    "couldn't contact marionette in time, rebooting")
                continue
            time.sleep(1)
            self.m.start_session()
            try:
                Wait(self.m, timeout=240).until(lambda m: m.find_element(
                    "id", "lockscreen-container").is_displayed())
                # It retuns a little early
                time.sleep(2)
                self.device = GaiaDevice(self.m)
                self.device.add_device_manager(self.dm)
                self.device.unlock()
                self.gaia_apps = GaiaApps(self.m)
            except (MarionetteException, IOError, socket.error) as e:
                self.run_log.error("got exception: %s, going to retry" % e)
                try:
                    self.m.delete_session()
                except:
                    # at least attempt to clear the session if possible
                    pass
                continue
            break
        else:
            raise Exception(
                "Couldn't restart the device in time, even after 3 tries")

    def readystate_wait(self, app):
        try:
            Wait(self.get_marionette(),
                 timeout=30).until(lambda m: m.execute_script(
                     "return window.document.readyState;") == "complete")
        except ScriptTimeoutException as e:
            return False
        return True

    def record_icons(self):
        self.device.touch_home_button()
        icons = self.m.find_elements("class name", "icon")
        self.num_apps = len(icons)

    def check_if_app_installed(self, timeout=180):
        # TODO: Find a better way to do this than checking homescreen
        # I hope there is one...
        self.device.touch_home_button()
        icons = self.m.find_elements("class name", "icon")
        start = time.time()
        end = start + 180
        found_icon = None
        claims_its_loaded = 0  # this is used in case 'loading' isn't applied immediately to the icon
        while time.time() < end:
            if not found_icon:
                icons = self.m.find_elements("class name", "icon")
                # We can't do set comparison b/c references change
                if len(icons) > self.num_apps:
                    for icon in icons:
                        if "loading" in icon.get_attribute("innerHTML"):
                            found_icon = icon
                            break
                    else:
                        claims_its_loaded += 1
                        if claims_its_loaded == 3:
                            return True
            else:
                if "loading" not in found_icon.get_attribute("innerHTML"):
                    return True
            time.sleep(2)
        return False
Ejemplo n.º 13
0
    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
    )
    assert [
        str(x) for x in m.find_element(HTMLElement.ID, "div1").find_elements(HTMLElement.SELECTOR, ".main")
    ] == server.TEST_FIND_ELEMENTS
    assert m.find_element(HTMLElement.ID, "id1").click()
    assert m.find_element(HTMLElement.ID, "id2").text() == server.TEST_GET_TEXT
    assert m.find_element(HTMLElement.ID, "id3").send_keys("Mozilla Firefox")
    assert m.find_element(HTMLElement.ID, "id3").value() == server.TEST_GET_VALUE
    assert m.find_element(HTMLElement.ID, "id3").clear()
    assert m.find_element(HTMLElement.ID, "id3").selected()
    assert m.find_element(HTMLElement.ID, "id1").equals(m.find_element(HTMLElement.TAG, "p"))
    assert m.find_element(HTMLElement.ID, "id3").enabled()
    assert m.find_element(HTMLElement.ID, "id3").displayed()
    assert m.find_element(HTMLElement.ID, "id3").get_attribute("value") == server.TEST_GET_VALUE
    assert m.delete_session()

    # verify a session is started automatically for us if needed
    assert m.switch_to_frame("frame1")
    assert m.switch_to_frame(1)
    assert m.switch_to_frame(m.find_element(HTMLElement.ID, "frameid"))
    assert m.switch_to_frame()
    assert m.get_window() == server.TEST_CURRENT_WINDOW
    assert m.set_context(m.CONTEXT_CHROME)
    assert m.delete_session()
Ejemplo n.º 14
0
    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)
    assert([str(x) for x in m.find_element(HTMLElement.ID, 'div1').find_elements(HTMLElement.SELECTOR, '.main')] == \
        server.TEST_FIND_ELEMENTS)
    assert(m.find_element(HTMLElement.ID, 'id1').click())
    assert(m.find_element(HTMLElement.ID, 'id2').text() == server.TEST_GET_TEXT)
    assert(m.find_element(HTMLElement.ID, 'id3').send_keys('Mozilla Firefox'))
    assert(m.find_element(HTMLElement.ID, 'id3').value() == server.TEST_GET_VALUE)
    assert(m.find_element(HTMLElement.ID, 'id3').clear())
    assert(m.find_element(HTMLElement.ID, 'id3').selected())
    assert(m.find_element(HTMLElement.ID, 'id1').equals(m.find_element(HTMLElement.TAG, 'p')))
    assert(m.find_element(HTMLElement.ID, 'id3').enabled())
    assert(m.find_element(HTMLElement.ID, 'id3').displayed())
    assert(m.find_element(HTMLElement.ID, 'id3').get_attribute('value') == server.TEST_GET_VALUE)
    assert(m.delete_session())

    # verify a session is started automatically for us if needed
    assert(m.switch_to_frame('frame1'))
    assert(m.switch_to_frame(1))
    assert(m.switch_to_frame(m.find_element(HTMLElement.ID, 'frameid')))
    assert(m.switch_to_frame())
    assert(m.get_window() == server.TEST_CURRENT_WINDOW)
    assert(m.set_context(m.CONTEXT_CHROME))
    assert(m.delete_session())
Ejemplo n.º 15
0
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 self.profileDir:
            self.restoreProfile()

    def waitForPort(self, timeout):
        """
        Wait for the marionette server to respond.
        Timeout parameter is 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):
        """
        Start a marionette session.
        If no host is given, then this will get the ip
        of the device, and set up networking if needed.
        """
        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()

    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,
        The 'prefs' is a string of user_prefs to add to the profile.
        If it is not set, it will default to a standard b2g testing profile.
        """
        if not prefs:
            prefs = """
user_pref("power.screen.timeout", 999999);
user_pref("devtools.debugger.force-local", false);
            """
        #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:
            output = 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, conn_type='eth0'):
        """
        Sets up networking.

        If conn_type is not set, it will assume eth0.
        """
        tries = 5
        while tries > 0:
            print "attempts left: %d" % tries
            try:
                self.shellCheckOutput(['netcfg', conn_type, 'dhcp'], timeout=10)
                if self.getIP():
                    return
            except DMError:
                pass
            tries = tries - 1
        raise DMError("Could not set up network connection")

    def restoreProfile(self):
        """
        Restores the original profile
        """
        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.
        """
        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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
Archivo: gcli.py Proyecto: AaronMT/gaia
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'},
            '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'},
            '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'},
            'unlock': {
                'function': self.unlock,
                'help': 'Unlock screen'}}

        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 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 set_setting(self, args):
        self.data_layer.set_setting(args.name, args.value)

    def unlock(self, args):
        self.lock_screen.unlock()
Ejemplo n.º 18
0
def dual_driving():
	try:
		print('Will connect to mobile..')
		mm = Marionette(host='localhost', port=2829)
		mm.start_session()
		if disable_ua_overrides_by_default:
			set_mozilla_pref(mm, 'general.useragent.site_specific_overrides', False)
			set_mozilla_pref(mm, 'general.useragent.updates.enabled', False)
			
		print('Will connect to desktop...')
		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 = []
		device_map = get_device_map()

		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
		#print(len(buglist))
		for item in buglist:
			if len(item) <= 1:
				print 'Warning: we expect data format ID    Summary    URL, something is missing'
				continue
			if i<start_at:
				i+=1
				continue
			buglink = ''
			if '://' not in item[0]: # assuming this is Bugzilla data from a tab-separated file - in other words a plain bug number
				# TODO: will we ever process lists of webcompat.com "plain numbers"??
				buglink = 'https://bugzilla.mozilla.org/show_bug.cgi?id=%s' % item[0]
			else: # we've got a bug tracker URL (right?)
				buglink = item[0]
			# users who have bugzilla's "load next bug in search" don't need an extra navigate() call
			if buglink not in md.get_url():
				print('Item %s, Loading bug %s'%(i,item[0]))
				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 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)
			try:
				mm.navigate(url)
				try_to_launch_url_in_android(device_map, url)
				print 'READY to analyze %s, \n%s' % (item[0], item[1])
			except:
				print('could not load %s, try again by pressing u\n\n' % url)
			options_menu(mm, url, md, device_map)
		mm.delete_session()
		md.delete_session()
	except Exception as err:
		print err
		try:
			mm.delete_session()
		except:
			pass
		try:
			md.delete_session()
		except:
			pass
Ejemplo n.º 19
0
Archivo: gcli.py Proyecto: bjacob/gaia
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'));")
Ejemplo n.º 20
0
class B2GMixin(object):
    profileDir = None
    userJS = "/data/local/user.js"
    marionette = None

    def __init__(self, host=None, marionette_port=2828, **kwargs):
        self.marionetteHost = host
        self.marionettePort = marionette_port

    def cleanup(self):
        if self.profileDir:
            self.restoreProfile()

    def waitForPort(self, timeout):
        """
        Wait for the marionette server to respond.
        Timeout parameter is 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):
        """
        Start a marionette session.
        If no host is given, then this will get the ip
        of the device, and set up networking if needed.
        """
        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()

    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,
        The 'prefs' is a string of user_prefs to add to the profile.
        If it is not set, it will default to a standard b2g testing profile.
        """
        if not prefs:
            prefs = """
user_pref("power.screen.timeout", 999999);
user_pref("devtools.debugger.force-local", false);
            """
        #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:
            output = 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, conn_type='eth0'):
        """
        Sets up networking.

        If conn_type is not set, it will assume eth0.
        """
        tries = 5
        while tries > 0:
            print "attempts left: %d" % tries
            try:
                self.shellCheckOutput(['netcfg', conn_type, 'dhcp'],
                                      timeout=10)
                if self.getIP():
                    return
            except DMError:
                pass
            tries = tries - 1
        raise DMError("Could not set up network connection")

    def restoreProfile(self):
        """
        Restores the original profile
        """
        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.
        """
        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
Ejemplo n.º 21
0
class B2GRunner(object):
    remote_profile_dir = None

    def __init__(self, dm, url, tmpdir, marionette_host=None, marionette_port=None):
        self.dm = dm
        self.url = url
        self.tmpdir = tmpdir
        self.userJS = "/data/local/user.js"
        self.marionette_host = marionette_host or 'localhost'
        self.marionette_port = marionette_port or 2828
        self.marionette = None

    def wait_for_port(self, timeout):
        starttime = datetime.datetime.now()
        while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.connect(('localhost', self.marionette_port))
                data = sock.recv(16)
                sock.close()
                if '"from"' in data:
                    return True
            except:
                import traceback
                print traceback.format_exc()
            time.sleep(1)
        return False

    def restart_b2g(self):
        #restart b2g so we start with a clean slate
        self.dm.checkCmd(['shell', 'stop', 'b2g'])
        # Wait for a bit to make sure B2G has completely shut down.
        time.sleep(10)
        self.dm.checkCmd(['shell', 'start', 'b2g'])
        
        #wait for marionette port to come up
        if not self.wait_for_port(30000):
            raise Exception("Could not communicate with Marionette port after restarting B2G")
        self.marionette = Marionette(self.marionette_host, self.marionette_port)
    
    def setup_profile(self):
        #remove previous user.js if there is one
        our_user_js = os.path.join(self.tmpdir, "user.js")
        if os.path.exists(our_user_js):
            os.remove(our_user_js)
        #copy profile
        try:
            self.dm.checkCmd(["pull", self.userJS, our_user_js])
        except subprocess.CalledProcessError:
            pass
        #if we successfully copied the profile, make a backup of the file
        if os.path.exists(our_user_js): 
            self.dm.checkCmd(['shell', 'dd', 'if=%s' % self.userJS, 'of=%s.orig' % self.userJS])
        user_js = open(our_user_js, 'a')
        user_js.write("""
user_pref("power.screen.timeout", 999999);
        """)
        user_js.close()
        self.dm.checkCmd(['push', our_user_js, self.userJS])
        self.restart_b2g()

    def start(self):
        #forward the marionette port
        self.dm.checkCmd(['forward',
                          'tcp:%s' % self.marionette_port,
                          'tcp:%s' % self.marionette_port])

        print "Setting up profile"
        self.setup_profile()
        #enable ethernet connection
        print "Running netcfg, it may take some time."
        self.dm.checkCmd(['shell', 'netcfg', 'eth0', 'dhcp'])
        #launch app
        session = self.marionette.start_session()
        if 'b2g' not in session:
            raise Exception("bad session value %s returned by start_session" % session)

        # start the tests by navigating to the mochitest url
        self.marionette.execute_script("window.location.href='%s';" % self.url)

    def stop(self):
        self.marionette.delete_session()
Ejemplo n.º 22
0
class TestRun(object):
    def __init__(self, adb="adb", serial=None):
        self.test_results = {}
        self.test_results_file = None
        self.m = None
        self.gaia_apps = None
        self.screenshot_path = None
        self.logcat_path = None
        self.app_name = None
        self.attempt = None
        self.num_apps = None
        self.device = None
        self.serial = serial
        self.port = None
        self.run_log = logging.getLogger('marketplace-test')
        if self.serial:
            self.dm = DeviceManagerADB(adbPath=adb, deviceSerial=serial)
        else:
            self.dm = DeviceManagerADB(adbPath=adb)

    def reset_marionette(self):
        try:
            self.m.delete_session()
        except Exception:
            pass
        self.m = None
        self.get_marionette()

    def get_marionette(self):
        if not self.m:
            self.m = Marionette(port=self.port)
            self.m.start_session()
            self.device = GaiaDevice(self.m)
            self.device.add_device_manager(self.dm)
            self.gaia_apps = GaiaApps(self.m)
        else:
            tries = 5
            while tries > 0:
                try:
                    self.m.get_url()
                    break
                except MarionetteException as e:
                    if "Please start a session" in str(e):
                        time.sleep(5)
                        self.m = Marionette(port=self.port)
                        self.m.start_session()
                        self.device = GaiaDevice(self.m)
                        self.device.add_device_manager(self.dm)
                        self.gaia_apps = GaiaApps(self.m)
                        tries -= 1
                    else:
                        raise e
            else:
                self.run_log.error("Can't connect to marionette, rebooting")
                self.restart_device()
        return self.m

    def write_to_file(self, data):
        with open("%s.tmp" % self.test_results_file, "w") as f:
            f.write(data)
        shutil.copyfile("%s.tmp" % self.test_results_file, self.test_results_file)

    def add_values(self, key, value):
        if self.serial:
            self.test_results["%s_%s" % (key, self.serial)] = value
        else:
            self.test_results["%s" % key] = value

    def add_result(self, passed=False, status=None, uninstalled_failure=False):
        values = {}
        if status:
            if not passed:
                values["status"] = "FAILED: %s" % status
            else:
                values["status"] = "PASS"
        if self.screenshot_path:
            values["screenshot"] = self.screenshot_path
        if self.logcat_path:
            values["logcat"] = self.logcat_path
        if uninstalled_failure:
            values["uninstalled_failure"] = uninstalled_failure
        entry = "%s_%s" % (self.app_name, self.attempt)
        self.test_results[entry] = values

    def launch_with_manifest(self, manifest):
        self.m.switch_to_frame() 
        result = self.m.execute_async_script("GaiaApps.launchWithManifestURL('%s')" % manifest, script_timeout=30000)
        if result == False:
            raise Exception("launch timed out")
        app = GaiaApp(frame=result.get('frame'),
                      src=result.get('src'),
                      name=result.get('name'),
                      origin=result.get('origin'))
        if app.frame_id is None:
            raise Exception("failed to launch; there is no app frame")
        self.m.switch_to_frame(app.frame_id)
        return app


    def uninstall_with_manifest(self, manifest):
        self.m.switch_to_frame() 
        script = """
        GaiaApps.locateWithManifestURL('%s',
                                       null,
                                       function uninstall(app) {
                                       navigator.mozApps.mgmt.uninstall(app);
                                       marionetteScriptFinished(true);
                                       });
        """
        result = self.m.execute_async_script(script % manifest, script_timeout=60000)
        if result != True:
            self.add_result(status="Failed to uninstall app with url '%s'" % manifest)
        return app

    def forward_port(self):
        # get unused port
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(('localhost', 0))
        addr, port = s.getsockname()
        s.close()

        dm_tries = 0
        self.run_log.info("using port %s" % port)
        while dm_tries < 20:
            if self.dm.forward("tcp:%d" % port, "tcp:2828") == 0:
                break
            dm_tries += 1
            time.sleep(3)
        else:
            return False
        self.port = port
        return True

    def restart_device(self, restart_tries=0):
        self.run_log.info("rebooting")
        # TODO restarting b2g doesn't seem to work... reboot then
        while restart_tries < 3:
            restart_tries += 1
            self.dm.reboot(wait=True)
            self.run_log.info("forwarding")
            if not self.forward_port():
                self.run_log.error("couldn't forward port in time, rebooting")
                continue
            self.m = Marionette(port=self.port)
            if not self.m.wait_for_port(180):
                self.run_log.error("couldn't contact marionette in time, rebooting")
                continue
            time.sleep(1)
            self.m.start_session()
            try:
                Wait(self.m, timeout=240).until(lambda m: m.find_element("id", "lockscreen-container").is_displayed())
                # It retuns a little early
                time.sleep(2)
                self.device = GaiaDevice(self.m)
                self.device.add_device_manager(self.dm)
                self.device.unlock()
                self.gaia_apps = GaiaApps(self.m)
            except (MarionetteException, IOError, socket.error) as e:
                self.run_log.error("got exception: %s, going to retry" % e)
                try:
                    self.m.delete_session()
                except:
                    # at least attempt to clear the session if possible
                    pass
                continue
            break
        else:
            raise Exception("Couldn't restart the device in time, even after 3 tries")

    def readystate_wait(self, app):
        try:
            Wait(self.get_marionette(), timeout=30).until(lambda m: m.execute_script("return window.document.readyState;") == "complete")
        except ScriptTimeoutException as e:
            return False
        return True  

    def record_icons(self):
        self.device.touch_home_button()
        icons = self.m.find_elements("class name", "icon")
        self.num_apps = len(icons)

    def check_if_app_installed(self, timeout=180):
        # TODO: Find a better way to do this than checking homescreen
        # I hope there is one...
        self.device.touch_home_button()
        icons = self.m.find_elements("class name", "icon")
        start = time.time()
        end = start + 180
        found_icon = None
        claims_its_loaded = 0 # this is used in case 'loading' isn't applied immediately to the icon
        while time.time() < end:
            if not found_icon:
                icons = self.m.find_elements("class name", "icon")
                # We can't do set comparison b/c references change
                if len(icons) > self.num_apps:
                    for icon in icons:
                        if "loading" in icon.get_attribute("innerHTML"):
                            found_icon = icon
                            break 
                    else:
                        claims_its_loaded += 1
                        if claims_its_loaded == 3:
                            return True
            else:
                if "loading" not in found_icon.get_attribute("innerHTML"):
                    return True
            time.sleep(2)
        return False
Ejemplo n.º 23
0
    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
Ejemplo n.º 24
0
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'},
            'listallapps': {
                'function': self.list_all_apps,
                'help': 'List all apps'},
            'listrunningapps': {
                'function': self.list_running_apps,
                'help': 'List the running apps'},
            '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 list_all_apps(self, args):
        for i, app in enumerate(sorted(self.apps.installed_apps,
                                       key=lambda a: a.name.lower())):
            print '%d: %s' % (i + 1, app.name)

    def list_running_apps(self, args):
        for i, app in enumerate(sorted(self.apps.running_apps,
                                       key=lambda a: a.name.lower())):
            print '%d: %s' % (i + 1, app.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'));")
Ejemplo n.º 25
0
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()
Ejemplo n.º 26
0
Archivo: gcli.py Proyecto: bjacob/gaia
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'));")
Ejemplo n.º 27
0
                      help='host:port of running Gecko instance to connect to')
    parser.add_option('--homedir', dest='homedir', action='store',
                      help='home directory of emulator files')
    options, tests = parser.parse_args()

    if not tests:
        parser.print_usage()
        parser.exit()

    if options.address:
        host, port = options.address.split(':')
        if options.emulator:
            m = Marionette(host=host, port=int(port),
                           connectToRunningEmulator=True,
                           homedir=options.homedir)
        else:
            m = Marionette(host=host, port=int(port))
    elif options.emulator:
        m = Marionette(emulator=True,
                       homedir=options.homedir)
    else:
        raise Exception("must specify --address or --emulator")

    assert(m.start_session())

    for test in tests:
        run_test(test, m)

    m.delete_session()

Ejemplo n.º 28
0
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
Ejemplo n.º 29
0
    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 = {
                'socket_timeout': options.marionette_socket_timeout,
                '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(timeout=options.marionette_port_timeout)

            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
Ejemplo n.º 30
0
class B2GRunner(object):
    remote_profile_dir = None

    def __init__(self,
                 dm,
                 url,
                 tmpdir,
                 marionette_host=None,
                 marionette_port=None):
        self.dm = dm
        self.url = url
        self.tmpdir = tmpdir
        self.userJS = "/data/local/user.js"
        self.marionette_host = marionette_host or 'localhost'
        self.marionette_port = marionette_port or 2828
        self.marionette = None

    def wait_for_port(self, timeout):
        starttime = datetime.datetime.now()
        while datetime.datetime.now() - starttime < datetime.timedelta(
                seconds=timeout):
            try:
                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                sock.connect(('localhost', self.marionette_port))
                data = sock.recv(16)
                sock.close()
                if '"from"' in data:
                    return True
            except:
                import traceback
                print traceback.format_exc()
            time.sleep(1)
        return False

    def restart_b2g(self):
        #restart b2g so we start with a clean slate
        self.dm.checkCmd(['shell', 'stop', 'b2g'])
        # Wait for a bit to make sure B2G has completely shut down.
        time.sleep(10)
        self.dm.checkCmd(['shell', 'start', 'b2g'])

        #wait for marionette port to come up
        if not self.wait_for_port(30000):
            raise Exception(
                "Could not communicate with Marionette port after restarting B2G"
            )
        self.marionette = Marionette(self.marionette_host,
                                     self.marionette_port)

    def setup_profile(self):
        #remove previous user.js if there is one
        our_user_js = os.path.join(self.tmpdir, "user.js")
        if os.path.exists(our_user_js):
            os.remove(our_user_js)
        #copy profile
        try:
            self.dm.checkCmd(["pull", self.userJS, our_user_js])
        except subprocess.CalledProcessError:
            pass
        #if we successfully copied the profile, make a backup of the file
        if os.path.exists(our_user_js):
            self.dm.checkCmd([
                'shell', 'dd',
                'if=%s' % self.userJS,
                'of=%s.orig' % self.userJS
            ])
        user_js = open(our_user_js, 'a')
        user_js.write("""
user_pref("power.screen.timeout", 999999);
        """)
        user_js.close()
        self.dm.checkCmd(['push', our_user_js, self.userJS])
        self.restart_b2g()

    def start(self):
        #forward the marionette port
        self.dm.checkCmd([
            'forward',
            'tcp:%s' % self.marionette_port,
            'tcp:%s' % self.marionette_port
        ])

        print "Setting up profile"
        self.setup_profile()
        #enable ethernet connection
        print "Running netcfg, it may take some time."
        self.dm.checkCmd(['shell', 'netcfg', 'eth0', 'dhcp'])
        #launch app
        session = self.marionette.start_session()
        if 'b2g' not in session:
            raise Exception("bad session value %s returned by start_session" %
                            session)

        # start the tests by navigating to the mochitest url
        self.marionette.execute_script("window.location.href='%s';" % self.url)

    def stop(self):
        self.marionette.delete_session()