Beispiel #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()
Beispiel #2
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")
Beispiel #3
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")
Beispiel #4
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()
Beispiel #5
0
def getTextContentViaMarionette(url):
    if Marionette is None:
        raise Exception("sorry this method is not supported because marionette driver couldn't be installed")
    client = Marionette("localhost", port=2828)
    print("client:", client)
    client.start_session()
    print("started session")
    client.set_script_timeout(30000)
    # not sure if one script ran after another
    return client.execute_async_script("""
        var win = window.open('""" + url + """');
        setTimeout(function(){
            textContent = win.document.body.textContent;
            win.close();
            marionetteScriptFinished(textContent);
        }, 15000);
    """)
Beispiel #6
0
def getTextContentViaMarionette(url):
    if Marionette is None:
        raise Exception(
            "sorry this method is not supported because marionette driver couldn't be installed"
        )
    client = Marionette("localhost", port=2828)
    print("client:", client)
    client.start_session()
    print("started session")
    client.set_script_timeout(30000)
    # not sure if one script ran after another
    return client.execute_async_script("""
        var win = window.open('""" + url + """');
        setTimeout(function(){
            textContent = win.document.body.textContent;
            win.close();
            marionetteScriptFinished(textContent);
        }, 15000);
    """)
Beispiel #7
0
def listapps():
    marionette = Marionette(host='localhost', port=2828)
    marionette.start_session()
    marionette.set_context(marionette.CONTEXT_CONTENT)
    marionette.set_script_timeout(1000)
    apps = marionette.execute_async_script("""
  let req = navigator.mozApps.mgmt.getAll();
  req.onsuccess = function() {
    let apps = req.result;
    let l = []
    for (let a of apps) {
      let data = {origin: a.origin, name: a.manifest.name};
      if (a.manifest.entry_points)
        data.entry_points = a.manifest.entry_points;
      l.push(data);
    }
    marionetteScriptFinished(l);
  };
""")
    for a in apps:
        print a["name"]
Beispiel #8
0
def listapps():
    marionette = Marionette(host='localhost', port=2828)
    marionette.start_session()
    marionette.set_context(marionette.CONTEXT_CONTENT)
    marionette.set_script_timeout(1000)
    apps = marionette.execute_async_script("""
  let req = navigator.mozApps.mgmt.getAll();
  req.onsuccess = function() {
    let apps = req.result;
    let l = []
    for (let a of apps) {
      let data = {origin: a.origin, name: a.manifest.name};
      if (a.manifest.entry_points)
        data.entry_points = a.manifest.entry_points;
      l.push(data);
    }
    marionetteScriptFinished(l);
  };
""")
    for a in apps:
        print a["name"]
Beispiel #9
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 unlock(self):
        """
        Unlocks the device, ensuring it will never go back to the lockscreen
        """
        if not self.marionette or not self.marionette.session:
            self.setupMarionette()

        success = self.marionette.execute_async_script("""
let setlock = window.wrappedJSObject.SettingsListener.getSettingsLock();
let obj = {'screen.timeout': 0};
setlock.set(obj);
waitFor(
function() {
window.wrappedJSObject.LockScreen.unlock();
waitFor(
function() {
finish(window.wrappedJSObject.LockScreen.locked);
},
function() {
return !window.wrappedJSObject.LockScreen.locked;
}
);
},
function() {
return !!window.wrappedJSObject.LockScreen;
}
);
""")
        if not success:
            raise DMError("Unable to unlock device")

    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
  waitFor(
    function() {
      window.wrappedJSObject.LockScreen.unlock();
      waitFor(
        function() {
          finish(window.wrappedJSObject.LockScreen.locked);
        },
        function() {
          return !window.wrappedJSObject.LockScreen.locked;
        }
      );
    },
    function() {
      return !!window.wrappedJSObject.LockScreen;
    }
  );
"""

from marionette import Marionette 

marionette = Marionette('localhost', 2828)
marionette.start_session()
marionette.import_script('gaia_apps.js')
marionette.set_script_timeout(60000)

marionette.execute_script(unlock)
result = marionette.execute_async_script("GaiaApps.launchWithName('%s')" % "NxtGenUG-QualityApps")

marionette.switch_to_frame(result.get("frame"))
pdb.set_trace()
Beispiel #11
0
class B2gExecutor(Executor):
    def __init__(self, app_name, app_id, device=False):
        self.device = device
        if self.device:
            call(['adb', 'forward', 'tcp:2828', 'tcp:2828'])
        self._app_name = app_name
        self._app_id = app_id
        self._marionette = Marionette()
        self._marionette.start_session()
        self._gaia_apps = GaiaApps(self._marionette)
        self._gaia_data = GaiaData(self._marionette)
        self._gaia_device = GaiaDevice(self._marionette)
        ''' Deprecated
        # https://github.com/mozilla-b2g/gaia/blob/b568b7ae8adb6ee3651bd75acbaaedff86a08912/tests/python/gaia-ui-tests/gaiatest/gaia_test.py
        js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
        self._marionette.import_script(js)
        js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_data_layer.js"))
        self._marionette.set_context(self._marionette.CONTEXT_CHROME)
        self._marionette.import_script(js)
        self._marionette.set_context(self._marionette.CONTEXT_CONTENT)

        # C:\Users\Jun-Wei\Desktop\b2g\battery\manifest.webapp
        #app = GaiaApps(self._marionette).launch(self._app_name)
        #app = GaiaApps(self._marionette).launch('Battery', manifest_url='C:/Users/Jun-Wei/Desktop/b2g/battery/manifest.webapp', entry_point='/index.html')

        app = GaiaApps(self._marionette).launch('Battery')
        print app.frame
        print app.src
        print app.origin
        print app.name
        #print g_app.manifest_url

        #self._app_frame = g_app.frame
        self._app_frame_id = app.frame
        self._app_src = app.src
        self._app_origin = app.origin
        #self.app_manifest_url = g_app.manifest_url

        #self.gaia_apps = GaiaApps(self.__marionette)
        #print self.gaia_apps.displayed_app.name
        #print self.gaia_apps.installed_apps
        #print self.gaia_apps.running_apps()
        #js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
        #self.__marionette.import_script(js)
        '''

    def fire_event(self, clickable):
        logger.info('fire_event: id: %s (xpath: %s)', clickable.get_id(),
                    clickable.get_xpath())
        try:
            # id staring with DomAnalyzer.serial_prefix is given by our monkey and should be ignored when locating
            if clickable.get_id() and not clickable.get_id().startswith(
                    DomAnalyzer.serial_prefix):
                self._marionette.find_element('id', clickable.get_id()).tap()
            elif clickable.get_xpath():
                self._marionette.find_element('xpath',
                                              clickable.get_xpath()).tap()
            else:
                logger.error(
                    'No id nor xpath for the clickable: id: %s (xpath: %s)',
                    clickable.get_id(), clickable.get_xpath())
                sys.exit()
        except (ElementNotVisibleException, InvalidElementStateException,
                NoSuchElementException):
            logger.info(
                'Element is not interactable in fire_event(): id: %s (xpath: %s)',
                clickable.get_id(), clickable.get_xpath())
        except Exception as e:
            logger.error(
                'Unknown Exception: %s in fire_event(): id: %s (xpath: %s)',
                str(e), clickable.get_id(), clickable.get_xpath())
            sys.exit()

    def fill_form(self, clickable):
        for f in clickable.get_forms():
            for input_field in f.get_inputs():
                try:
                    if input_field.get_id() and not input_field.get_id(
                    ).startswith(DomAnalyzer.serial_prefix):
                        self._marionette.find_element(
                            'id', input_field.get_id()).send_keys(
                                input_field.get_value())
                    elif input_field.get_xpath():
                        self._marionette.find_element(
                            'xpath', input_field.get_xpath()).send_keys(
                                input_field.get_value())
                    else:
                        logger.error(
                            'No id nor xpath for an input field in the form id: %s (xpath: %s)',
                            f.get_id(), f.get_xpath())
                        sys.exit()
                except (ElementNotVisibleException,
                        InvalidElementStateException, NoSuchElementException):
                    logger.info(
                        'Element is not interactable in fill_form(): id: %s (xpath: %s)',
                        f.get_id(), f.get_xpath())
                except Exception as e:
                    logger.error(
                        'Unknown Exception: %s in fill_form(): id: %s (xpath: %s)',
                        str(e), f.get_id(), f.get_xpath())
                    sys.exit()

    def empty_form(self, clickable):
        for f in clickable.get_forms():
            for input_field in f.get_inputs():
                try:
                    if input_field.get_id() and not input_field.get_id(
                    ).startswith(DomAnalyzer.serial_prefix):
                        self._marionette.find_element(
                            'id', input_field.get_id()).clear()
                    elif input_field.get_xpath():
                        self._marionette.find_element(
                            'xpath', input_field.get_xpath()).clear()
                    else:
                        logger.error(
                            'No id nor xpath for an input field in the form %s (%s)',
                            f.get_id(), f.get_xpath())
                        sys.exit()
                except (ElementNotVisibleException,
                        InvalidElementStateException, NoSuchElementException):
                    logger.info(
                        'Element is not interactable in empty_form(): id: %s (xpath: %s)',
                        f.get_id(), f.get_xpath())
                except Exception as e:
                    logger.error(
                        'Unknown Exception: %s in empty_form(): id: %s (xpath: %s)',
                        str(e), f.get_id(), f.get_xpath())
                    sys.exit()

    def get_source(self):
        return self._marionette.page_source.encode(sys.stdout.encoding,
                                                   'ignore')

    def get_screenshot(self, clickable=None):
        element = None
        if clickable:
            try:
                if clickable.get_id() and not clickable.get_id().startswith(
                        DomAnalyzer.serial_prefix):
                    element = self._marionette.find_element(
                        'id', clickable.get_id())
                elif clickable.get_xpath():
                    element = self._marionette.find_element(
                        'xpath', clickable.get_xpath())
                else:
                    logger.error(
                        'No id nor xpath for the clickable: id: %s (xpath: %s)',
                        clickable.get_id(), clickable.get_xpath())
                    sys.exit()
            except (ElementNotVisibleException, InvalidElementStateException,
                    NoSuchElementException):
                logger.info(
                    'Element is not interactable in get_screenshot(): id: %s (xpath: %s)',
                    clickable.get_id(), clickable.get_xpath())
            except Exception as e:
                logger.error(
                    'Unknown Exception: %s in get_screenshot(): id: %s (xpath: %s)',
                    str(e), clickable.get_id(), clickable.get_xpath())
                sys.exit()
        if not element:
            # set context to CHROME to capture whole screen
            # system frame e.g. FileNotFound cannot be captured without CONTEXT_CHROME (Don't know why)
            self._marionette.set_context(self._marionette.CONTEXT_CHROME)
        screenshot = self._marionette.screenshot(element)
        self._marionette.set_context(self._marionette.CONTEXT_CONTENT)
        return screenshot

    def switch_to_frame(self, by, frame_str):
        """
        :param by: options: "id", "xpath", "link text", "partial link text", "name",
        "tag name", "class name", "css selector", "anon attribute"
        """
        # self.switch_to_top_frame()
        frame = self._marionette.find_element(by, frame_str)
        self._marionette.switch_to_frame(frame)

    def switch_to_top_frame(self):
        self._marionette.switch_to_frame()  # switch to the top-level frame

    def restart_app(self):
        # remember to disable screen timeout and screen lock before testing
        # todo: open b2g simulator, install app,
        # unlock_screen
        # self._marionette.execute_script('window.wrappedJSObject.lockScreen.unlock();')

        self.kill_all_apps()
        # kill_all_apps() will also kill the 'homescreen app' on real device
        # so trigger a home event to restore homescreen
        if self.device:
            self._dispatch_home_button_event()
        self.clear_data()
        self.touch_home_button()

        # launch the app
        self._gaia_apps.launch(self._app_name)
        ''' Deprecated
        if self.device:
            icon = self._marionette.find_element('xpath', "//li[contains(@aria-label, '" + self._app_name + "')]")
        else:
            icon = self._marionette.find_element('xpath', "//div[contains(@class, 'icon')]//span[contains(text(),'" + self._app_name + "')]")
        icon.tap()
        '''
        time.sleep(5)  # wait for app screen
        self._marionette.switch_to_frame()
        # this wait seems not working, need to find another useful one
        Wait(self._marionette).until(lambda m: m.find_element(
            'css selector', "iframe[data-url*='" + self._app_id + "']").
                                     is_displayed())
        app_frame = self._marionette.find_element(
            'css selector', "iframe[data-url*='" + self._app_id + "']")
        self._marionette.switch_to_frame(app_frame)

    def touch_home_button(self):
        # ref: https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L751
        apps = self._gaia_apps
        if apps.displayed_app.name.lower() != 'homescreen':
            # touching home button will return to homescreen
            self._dispatch_home_button_event()
            Wait(self._marionette).until(
                lambda m: apps.displayed_app.name.lower() == 'homescreen')
            apps.switch_to_displayed_app()
        else:
            apps.switch_to_displayed_app()
            mode = self._marionette.find_element(By.TAG_NAME,
                                                 'body').get_attribute('class')
            self._dispatch_home_button_event()
            apps.switch_to_displayed_app()
            if 'edit-mode' in mode:
                # touching home button will exit edit mode
                Wait(self._marionette).until(lambda m: m.find_element(
                    By.TAG_NAME, 'body').get_attribute('class') != mode)
            else:
                # touching home button inside homescreen will scroll it to the top
                Wait(self._marionette).until(lambda m: m.execute_script(
                    "return window.wrappedJSObject.scrollY") == 0)

    def _dispatch_home_button_event(self):
        self._gaia_device._dispatch_home_button_event()
        ''' Deprecated
        self._marionette.switch_to_frame()
        self._marionette.execute_script("window.wrappedJSObject.dispatchEvent(new Event('home'));")
        '''
        time.sleep(0.5)

    def clear_data(self):
        # for now, clear contact data
        # https://github.com/mozilla-b2g/gaia/blob/v2.2/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L208
        self._marionette.set_context(self._marionette.CONTEXT_CHROME)
        result = self._marionette.execute_async_script(
            'return GaiaDataLayer.removeAllContacts();')
        assert result, 'Unable to remove all contacts'
        self._marionette.set_context(self._marionette.CONTEXT_CONTENT)
        time.sleep(0.5)

    def kill_all_apps(self):
        self._marionette.switch_to_frame()
        self._marionette.execute_async_script("""
        // Kills all running apps, except the homescreen.
        function killAll() {
          let manager = window.wrappedJSObject.appWindowManager;

          let apps = manager.getApps();
          for (let id in apps) {
            let origin = apps[id].origin;
            if (origin.indexOf('verticalhome') == -1) {
              manager.kill(origin);
            }
          }
        };
        killAll();
        // return true so execute_async_script knows the script is complete
        marionetteScriptFinished(true);
        """)
        time.sleep(0.5)
Beispiel #12
0
class B2gExecutor(Executor):
    def __init__(self, app_name, app_id, device=False):
        self.device = device
        if self.device:
            call(['adb', 'forward', 'tcp:2828', 'tcp:2828'])
        self._app_name = app_name
        self._app_id = app_id
        self._marionette = Marionette()
        self._marionette.start_session()
        self._gaia_apps = GaiaApps(self._marionette)
        self._gaia_data = GaiaData(self._marionette)
        self._gaia_device = GaiaDevice(self._marionette)
        ''' Deprecated
        # https://github.com/mozilla-b2g/gaia/blob/b568b7ae8adb6ee3651bd75acbaaedff86a08912/tests/python/gaia-ui-tests/gaiatest/gaia_test.py
        js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
        self._marionette.import_script(js)
        js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_data_layer.js"))
        self._marionette.set_context(self._marionette.CONTEXT_CHROME)
        self._marionette.import_script(js)
        self._marionette.set_context(self._marionette.CONTEXT_CONTENT)

        # C:\Users\Jun-Wei\Desktop\b2g\battery\manifest.webapp
        #app = GaiaApps(self._marionette).launch(self._app_name)
        #app = GaiaApps(self._marionette).launch('Battery', manifest_url='C:/Users/Jun-Wei/Desktop/b2g/battery/manifest.webapp', entry_point='/index.html')

        app = GaiaApps(self._marionette).launch('Battery')
        print app.frame
        print app.src
        print app.origin
        print app.name
        #print g_app.manifest_url

        #self._app_frame = g_app.frame
        self._app_frame_id = app.frame
        self._app_src = app.src
        self._app_origin = app.origin
        #self.app_manifest_url = g_app.manifest_url

        #self.gaia_apps = GaiaApps(self.__marionette)
        #print self.gaia_apps.displayed_app.name
        #print self.gaia_apps.installed_apps
        #print self.gaia_apps.running_apps()
        #js = os.path.abspath(os.path.join(__file__, os.path.pardir, 'atoms', "gaia_apps.js"))
        #self.__marionette.import_script(js)
        '''

    def fire_event(self, clickable):
        logger.info('fire_event: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath())
        try:
            # id staring with DomAnalyzer.serial_prefix is given by our monkey and should be ignored when locating
            if clickable.get_id() and not clickable.get_id().startswith(DomAnalyzer.serial_prefix):
                self._marionette.find_element('id', clickable.get_id()).tap()
            elif clickable.get_xpath():
                self._marionette.find_element('xpath', clickable.get_xpath()).tap()
            else:
                logger.error('No id nor xpath for the clickable: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath())
                sys.exit()
        except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException):
            logger.info('Element is not interactable in fire_event(): id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath())
        except Exception as e:
            logger.error('Unknown Exception: %s in fire_event(): id: %s (xpath: %s)', str(e), clickable.get_id(), clickable.get_xpath())
            sys.exit()

    def fill_form(self, clickable):
        for f in clickable.get_forms():
            for input_field in f.get_inputs():
                try:
                    if input_field.get_id() and not input_field.get_id().startswith(DomAnalyzer.serial_prefix):
                        self._marionette.find_element('id', input_field.get_id()).send_keys(input_field.get_value())
                    elif input_field.get_xpath():
                        self._marionette.find_element('xpath', input_field.get_xpath()).send_keys(input_field.get_value())
                    else:
                        logger.error('No id nor xpath for an input field in the form id: %s (xpath: %s)', f.get_id(), f.get_xpath())
                        sys.exit()
                except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException):
                    logger.info('Element is not interactable in fill_form(): id: %s (xpath: %s)', f.get_id(), f.get_xpath())
                except Exception as e:
                    logger.error('Unknown Exception: %s in fill_form(): id: %s (xpath: %s)', str(e), f.get_id(), f.get_xpath())
                    sys.exit()

    def empty_form(self, clickable):
        for f in clickable.get_forms():
            for input_field in f.get_inputs():
                try:
                    if input_field.get_id() and not input_field.get_id().startswith(DomAnalyzer.serial_prefix):
                        self._marionette.find_element('id', input_field.get_id()).clear()
                    elif input_field.get_xpath():
                        self._marionette.find_element('xpath', input_field.get_xpath()).clear()
                    else:
                        logger.error('No id nor xpath for an input field in the form %s (%s)', f.get_id(), f.get_xpath())
                        sys.exit()
                except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException):
                    logger.info('Element is not interactable in empty_form(): id: %s (xpath: %s)', f.get_id(), f.get_xpath())
                except Exception as e:
                    logger.error('Unknown Exception: %s in empty_form(): id: %s (xpath: %s)', str(e), f.get_id(), f.get_xpath())
                    sys.exit()

    def get_source(self):
        return self._marionette.page_source.encode(sys.stdout.encoding, 'ignore')

    def get_screenshot(self, clickable=None):
        element = None
        if clickable:
            try:
                if clickable.get_id() and not clickable.get_id().startswith(DomAnalyzer.serial_prefix):
                    element = self._marionette.find_element('id', clickable.get_id())
                elif clickable.get_xpath():
                    element = self._marionette.find_element('xpath', clickable.get_xpath())
                else:
                    logger.error('No id nor xpath for the clickable: id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath())
                    sys.exit()
            except (ElementNotVisibleException, InvalidElementStateException, NoSuchElementException):
                logger.info('Element is not interactable in get_screenshot(): id: %s (xpath: %s)', clickable.get_id(), clickable.get_xpath())
            except Exception as e:
                logger.error('Unknown Exception: %s in get_screenshot(): id: %s (xpath: %s)', str(e), clickable.get_id(), clickable.get_xpath())
                sys.exit()
        if not element:
            # set context to CHROME to capture whole screen
            # system frame e.g. FileNotFound cannot be captured without CONTEXT_CHROME (Don't know why)
            self._marionette.set_context(self._marionette.CONTEXT_CHROME)
        screenshot = self._marionette.screenshot(element)
        self._marionette.set_context(self._marionette.CONTEXT_CONTENT)
        return screenshot

    def switch_to_frame(self, by, frame_str):
        """
        :param by: options: "id", "xpath", "link text", "partial link text", "name",
        "tag name", "class name", "css selector", "anon attribute"
        """
        # self.switch_to_top_frame()
        frame = self._marionette.find_element(by, frame_str)
        self._marionette.switch_to_frame(frame)

    def switch_to_top_frame(self):
        self._marionette.switch_to_frame()  # switch to the top-level frame

    def restart_app(self):
        # remember to disable screen timeout and screen lock before testing
        # todo: open b2g simulator, install app,
        # unlock_screen
        # self._marionette.execute_script('window.wrappedJSObject.lockScreen.unlock();')

        self.kill_all_apps()
        # kill_all_apps() will also kill the 'homescreen app' on real device
        # so trigger a home event to restore homescreen
        if self.device:
            self._dispatch_home_button_event()
        self.clear_data()
        self.touch_home_button()

        # launch the app
        self._gaia_apps.launch(self._app_name)
        ''' Deprecated
        if self.device:
            icon = self._marionette.find_element('xpath', "//li[contains(@aria-label, '" + self._app_name + "')]")
        else:
            icon = self._marionette.find_element('xpath', "//div[contains(@class, 'icon')]//span[contains(text(),'" + self._app_name + "')]")
        icon.tap()
        '''
        time.sleep(5)  # wait for app screen
        self._marionette.switch_to_frame()
        # this wait seems not working, need to find another useful one
        Wait(self._marionette).until(lambda m: m.find_element('css selector', "iframe[data-url*='" + self._app_id + "']").is_displayed())
        app_frame = self._marionette.find_element('css selector', "iframe[data-url*='" + self._app_id + "']")
        self._marionette.switch_to_frame(app_frame)

    def touch_home_button(self):
        # ref: https://github.com/mozilla-b2g/gaia/blob/master/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L751
        apps = self._gaia_apps
        if apps.displayed_app.name.lower() != 'homescreen':
            # touching home button will return to homescreen
            self._dispatch_home_button_event()
            Wait(self._marionette).until(
                lambda m: apps.displayed_app.name.lower() == 'homescreen')
            apps.switch_to_displayed_app()
        else:
            apps.switch_to_displayed_app()
            mode = self._marionette.find_element(By.TAG_NAME, 'body').get_attribute('class')
            self._dispatch_home_button_event()
            apps.switch_to_displayed_app()
            if 'edit-mode' in mode:
                # touching home button will exit edit mode
                Wait(self._marionette).until(lambda m: m.find_element(
                    By.TAG_NAME, 'body').get_attribute('class') != mode)
            else:
                # touching home button inside homescreen will scroll it to the top
                Wait(self._marionette).until(lambda m: m.execute_script(
                    "return window.wrappedJSObject.scrollY") == 0)

    def _dispatch_home_button_event(self):
        self._gaia_device._dispatch_home_button_event()
        ''' Deprecated
        self._marionette.switch_to_frame()
        self._marionette.execute_script("window.wrappedJSObject.dispatchEvent(new Event('home'));")
        '''
        time.sleep(0.5)

    def clear_data(self):
        # for now, clear contact data
        # https://github.com/mozilla-b2g/gaia/blob/v2.2/tests/python/gaia-ui-tests/gaiatest/gaia_test.py#L208
        self._marionette.set_context(self._marionette.CONTEXT_CHROME)
        result = self._marionette.execute_async_script('return GaiaDataLayer.removeAllContacts();')
        assert result, 'Unable to remove all contacts'
        self._marionette.set_context(self._marionette.CONTEXT_CONTENT)
        time.sleep(0.5)

    def kill_all_apps(self):
        self._marionette.switch_to_frame()
        self._marionette.execute_async_script("""
        // Kills all running apps, except the homescreen.
        function killAll() {
          let manager = window.wrappedJSObject.appWindowManager;

          let apps = manager.getApps();
          for (let id in apps) {
            let origin = apps[id].origin;
            if (origin.indexOf('verticalhome') == -1) {
              manager.kill(origin);
            }
          }
        };
        killAll();
        // return true so execute_async_script knows the script is complete
        marionetteScriptFinished(true);
        """)
        time.sleep(0.5)
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
Beispiel #14
0
class TestCase(tornado.testing.AsyncTestCase):
    def __init__(self, *args, **kwargs):
        #self.config = kwargs.pop("config")
        self.handler = kwargs.pop('handler')
        self.io_loop = kwargs.pop('io_loop')
        self.cert_test_app = None
        super(TestCase, self).__init__(*args, **kwargs)

    def setUp(self):
        super(TestCase, self).setUp()
        # import environment
        # from environment import InProcessTestEnvironment
        # self.environment = environment.get(InProcessTestEnvironment)
        # self.server = self.environment.server
        self.marionette = None

        self.create_marionette()
        self.io_loop.run_sync(self.use_cert_app)

    def tearDown(self):
        super(TestCase, self).tearDown()
        self.io_loop.run_sync(self.close_cert_app)

    def create_marionette(self):
        if not self.marionette or not self.marionette.session:
            self.marionette = Marionette()
            self.marionette.start_session()

    @tornado.gen.coroutine
    def use_cert_app(self):
        # app management is done in the system app
        self.marionette.switch_to_frame()
        self.marionette.import_script("tests/app_management.js")
        script = "GaiaApps.launchWithName('CertTest App');"
        try:
            self.cert_test_app = self.marionette.execute_async_script(script, script_timeout=5000)
            self.marionette.switch_to_frame(self.cert_test_app["frame"])
            self.assertTrue('certtest' in self.marionette.get_url())
        except MarionetteException as e:
            ok = yield self.instruct("Could not launch CertTest app automatically." \
                                     "Please launch by hand then hit OK to continue.")
            self.assertTrue(ok, "Could not launch CertTest app")
        except Exception as e:
            message = "Unexpected exception: %s" % e
            yield self.instruct(message)
            self.fail(message)

    @tornado.gen.coroutine
    def close_cert_app(self):
        self.marionette.import_script("tests/app_management.js")
        # app management is done in the system app
        self.marionette.switch_to_frame()
        script = "GaiaApps.kill('%s');" % self.cert_test_app["origin"]
        try:
            self.marionette.execute_async_script(script, script_timeout=5000)
            self.assertTrue('certtest' not in self.marionette.get_url())
        except MarionetteException as e:
            ok = yield self.instruct("Could not close CertTest app automatically." \
                                     "Please close by hand then hit OK to continue.")
            self.assertTrue(ok, "Could not close CertTest app")
        except Exception as e:
            message = "Unexpected exception: %s" % e
            yield self.instruct(message)
            self.fail(message)

    def get_new_ioloop(self):
        return self.io_loop

    def prompt(self, message):
        """Prompt the user for a reply.  Returns a future which must be
        yielded.

        This will trigger an overlay  in the host browser window
        which can be used to tell the user to perform an action or to
        input some manual data for us to work on.

        Sample usage::

            answer = yield prompt("What's the meaning of life?")
            assert answer == 42

        This function is a simple wrapper for ``tornado.gen.Task``,
        and is equivalent to the usage of that.

        :param message: The question to ask or message to give the
            user.

        :returns: A generator which must be yielded. Once yielded,
                  the return value will be the value of the prompt,
                  or False if the user hit 'Cancel'

        """

        return tornado.gen.Task(self.handler.get_user_input, message)

    def instruct(self, message):
        """Presents the user with an instruction.  Returns a future which
        must be yielded.

        This will trigger an overlay in the host browser window
        which can be used to tell the user to perform an action or to
        input some manual data for us to work on.

        Sample usage::

            answer = yield prompt("What's the meaning of life?")
            assert answer == 42

        This function is a simple wrapper for ``tornado.gen.Task``,
        and is equivalent to the usage of that.

        :param message: The instruction you want to give the user

        :returns: A generator which must be yielded. Once yielded,
                  the reutrn value will be either True if they 
                  succeeded or False if they did not.

        """

        return tornado.gen.Task(self.handler.instruct_user, message)
Beispiel #15
0
class Runner(object):

    _INPUT_NONE = ''
    _INPUT_EXIT_COMMAND = 'exit'
    _INPUT_MULTIPLE_LINE = ' \\'
    _INPUT_COMMAND_PREFIX = ':'
    _INPUT_SYSTEM_APP_KEYWORD = 'system'

    _KEYBOARD_FRAME_NAME = 'app://keyboard.gaiamobile.org/index.html'

    _is_async = False
    _sync_prompt = '>>> '
    _async_prompt = 'a>> '
    _prompt = _sync_prompt

    def __init__(self, **kwargs):
        # Added parser
        parser = OptionParser()
        parser.add_option(
            '-a',
            '--address',
            action='store',
            type='string',
            dest='address',
            default='localhost',
            help='The host address of b2g instance. Default=localhost')
        parser.add_option('-p',
                          '--port',
                          action='store',
                          type='int',
                          dest='port',
                          default=2828,
                          help='The port of b2g instance.')
        parser.add_option('-l',
                          '--list',
                          action='store_true',
                          dest='enable_list',
                          default='False',
                          help='List all apps of b2g instance. Default=False')
        parser.add_option('-c', '--connect',
                          action='store', type='string', dest='connect',
                          default=None,
                          help='Connect to the App iframe.' \
                               'Use # ID or App URL to connect.')

        (options, args) = parser.parse_args()
        self.connect = options.connect

        # start marionette session
        self.m = Marionette(options.address, options.port)
        self.m.start_session()

        # list all iframes
        if options.enable_list:
            self.list_all_iframes()
        # list active iframes
        elif self.connect == None:
            self.list_active_iframes()

        # connect to App
        if self.connect == None:
            exit(0)
        else:
            # connect App
            print 'Start...'
            if self.open_app(self.connect):
                self.start_js()
            else:
                exit(-1)

    def switch_sync_async(self):
        self._is_async = not self._is_async
        self._prompt = self._async_prompt if self._is_async else self._sync_prompt
        print 'Swith to', ('Async'
                           if self._is_async else 'Sync'), 'JS execution'

    def start_js(self):
        print 'Enter \'%s\' or Crtl+D to exit the shell.' % self._INPUT_EXIT_COMMAND
        print 'And enter \':h\' for more commands.'
        try:
            while True:
                input = raw_input(self._prompt)
                # if input is EXIT command, exit this program
                if input.lower() == self._INPUT_EXIT_COMMAND:
                    self.goodbye()
                    break

                # if input is NONE, then do nothing and keep going...
                elif input == self._INPUT_NONE:
                    continue

                # if input start with ":", it should be the command.
                elif input.startswith(self._INPUT_COMMAND_PREFIX):
                    CmdDispatcher(self, input)

                # if the postfix of input is MULTIPLE_LINE, then record this line and wait the next line until no input with MULTIPLE_LINE.
                elif input.endswith(self._INPUT_MULTIPLE_LINE):
                    input_multiple = input[:len(input) - 1] + '; '
                    while True:
                        next_input = raw_input('... ')
                        if next_input.endswith(self._INPUT_MULTIPLE_LINE):
                            input_multiple = input_multiple + next_input[:len(
                                next_input) - 1] + '; '
                            pass
                        else:
                            input_multiple = input_multiple + next_input + '; '
                            print self.execute_script(input_multiple)
                            break

                # if input is NOT above inputs, then run marionette.execute_script(INPUT)/marionette.execute_async_script(INPUT)
                # and print return value.
                else:
                    print self.execute_script(input)

        except EOFError:
            self.goodbye()
            exit()
        except Exception as e:
            print e
            if self.open_app(-1):
                self.start_js()
        exit()

    def execute_script(self, script):
        try:
            if self._is_async:
                return self.m.execute_async_script(script)
            else:
                return self.m.execute_script(script)
        except Exception as ex:
            print str(ex.message)

    def goodbye(self):
        print 'End. Bye!!'

    def open_app(self, input):
        try:
            # connect App by ID
            app_id = int(input)
            if app_id < 0:
                print 'Connect to', self._get_system_URL()
                self.set_current_frame(self._get_system_URL())
                self.m.switch_to_frame()
            else:
                iframes = self.get_all_iframes_id_name_pair()
                print 'Connect to', iframes[str(app_id)]
                self.set_current_frame(iframes[str(app_id)])
                if iframes[str(app_id)] == self._KEYBOARD_FRAME_NAME:
                    self.m.switch_to_frame(app_id, False)
                else:
                    self.m.switch_to_frame(app_id)
            return True

        except (ValueError):
            # connect to System app
            if (input.lower() == self._INPUT_SYSTEM_APP_KEYWORD) or (
                    input.lower() in self._get_system_URL()):
                print 'Connect to', self._get_system_URL()
                self.set_current_frame(self._get_system_URL())
                self.m.switch_to_frame()
                return True

            # connect App by substring
            iframes = self.get_all_iframes_id_name_pair()
            suitable_iframes = {}
            for k, v in iframes.items():
                if input in v:
                    suitable_iframes[k] = v
            # connect to App if there is one fit
            if len(suitable_iframes) == 1:
                target = suitable_iframes.keys()[0]
                print 'Connect to', suitable_iframes.values()[0]
                self.set_current_frame(suitable_iframes.values()[0])
                if suitable_iframes.values()[0] == self._KEYBOARD_FRAME_NAME:
                    self.m.switch_to_frame(int(target), False)
                else:
                    self.m.switch_to_frame(int(target))
                return True
            # exit if there are more than one app fit the query
            elif len(suitable_iframes) > 1:
                print 'There are more than one Apps fit the query string [', input, '].'
                print '{0:2s} {1:s}'.format('#', 'App URL')
                for k, v in sorted(suitable_iframes.items()):
                    print '{0:2s} {1:s}'.format(k, v)
                return False
            # exit if there is no app fit the query
            else:
                print 'There is no App fit the query string [', input, '].'
                return False

    def set_current_frame(self, frame_name):
        self._current_frame = frame_name

    def get_current_frame(self):
        return self._current_frame

    def switch_to_system_frame(self):
        self.m.switch_to_frame()

    def _get_system_URL(self):
        self.switch_to_system_frame()
        system_URL = self.m.execute_script('return document.URL')
        return system_URL

    def _get_all_iframes(self):
        self.switch_to_system_frame()
        iframes = self.m.execute_script(
            'return document.getElementsByTagName("iframe")')
        return iframes

    def get_all_iframes_id_name_pair(self):
        iframes = self._get_all_iframes()
        result = {}
        for idx in range(0, iframes['length']):
            iframe = iframes[str(idx)]
            result[str(idx)] = iframe.get_attribute('src')
        return result

    def list_all_iframes(self):
        iframes = self._get_all_iframes()
        print '{0:2s} {1:7s} {2:s}'.format('#', 'Status', 'App URL')
        print '{0:2s} {1:7s} {2:s}'.format('-1', '', self._get_system_URL())
        for idx in range(0, iframes['length']):
            iframe = iframes[str(idx)]
            print '{0:2s} {1:7s} {2:s}'.format(
                str(idx), ('active' if iframe.is_displayed() else ''),
                iframe.get_attribute('src'))

    def list_active_iframes(self):
        iframes = self._get_all_iframes()
        print '{0:2s} {1:7s} {2:s}'.format('#', 'Status', 'App URL')
        result = {}
        for idx in range(0, iframes['length']):
            iframe = iframes[str(idx)]
            if iframe.is_displayed():
                result[str(idx)] = iframe
        for idx, iframe in result.items():
            print '{0:2s} {1:7s} {2:s}'.format(
                idx, ('active' if iframe.is_displayed() else ''),
                iframe.get_attribute('src'))

    # TODO: seems like should using Javascript to get the idx of each iframe!?
    def get_all_iframes_by_marionette(self):
        iframes = self.m.find_elements('css selector', 'iframe')
        return iframes

    def list_all_iframes_by_marionette(self):
        iframes = self.get_all_iframes_by_marionette()
        for iframe in iframes:
            print iframe.get_attribute('src')

    def list_active_iframes_by_marionette(self):
        iframes = self.get_all_iframes_by_marionette()
        result = []
        for iframe in iframes:
            if iframe.is_displayed():
                result.append(iframe)
        for iframe in result:
            print iframe.get_attribute('src')
Beispiel #16
0
 assert(m.get_windows() == server.TEST_WINDOW_LIST)
 assert(m.switch_to_window('window2'))
 assert(m.window == 'window2')
 assert(m.close_window('window2'))
 assert(m.set_script_timeout(1000))
 assert(m.set_search_timeout(500))
 assert(m.get_url() == server.TEST_URL)
 assert(m.navigate(server.TEST_URL))
 assert(m.go_back())
 assert(m.go_forward())
 assert(m.refresh())
 assert(m.execute_script(server.TEST_EXECUTE_SCRIPT))
 assert(m.execute_js_script(server.TEST_EXECUTE_SCRIPT))
 assert(m.execute_js_script(server.TEST_EXECUTE_SCRIPT, server.TEST_EXECUTE_SCRIPT_ARGS))
 assert(m.execute_script(server.TEST_EXECUTE_SCRIPT, server.TEST_EXECUTE_SCRIPT_ARGS))
 assert(m.execute_async_script(server.TEST_EXECUTE_SCRIPT))
 assert(m.execute_async_script(server.TEST_EXECUTE_SCRIPT, server.TEST_EXECUTE_SCRIPT_ARGS))
 assert(str(m.find_element(HTMLElement.CLASS, 'heading')) == server.TEST_FIND_ELEMENT)
 assert([str(x) for x in m.find_elements(HTMLElement.TAG, 'p')] == server.TEST_FIND_ELEMENTS)
 assert(str(m.find_element(HTMLElement.CLASS, 'heading').find_element(HTMLElement.TAG, 'h1')) == server.TEST_FIND_ELEMENT)
 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())
Beispiel #17
0
class Runner(object):

    _INPUT_NONE = ''
    _INPUT_EXIT_COMMAND = 'exit'
    _INPUT_MULTIPLE_LINE = ' \\'
    _INPUT_COMMAND_PREFIX = ':'
    _INPUT_SYSTEM_APP_KEYWORD = 'system'

    _is_async = False
    _sync_prompt = '>>> '
    _async_prompt = 'a>> '
    _prompt = _sync_prompt

    def __init__(self, **kwargs):
        # Added parser
        parser = OptionParser()
        parser.add_option('-a', '--address',
                          action='store', type='string', dest='address',
                          default='localhost',
                          help='The host address of b2g instance. Default=localhost')
        parser.add_option('-p', '--port',
                          action='store', type='int', dest='port',
                          default=2828,
                          help='The port of b2g instance.')
        parser.add_option('-l', '--list',
                          action='store_true', dest='enable_list',
                          default='False',
                          help='List all apps of b2g instance. Default=False')
        parser.add_option('-c', '--connect',
                          action='store', type='string', dest='connect',
                          default=None,
                          help='Connect to the App iframe.' \
                               'Use # ID or App URL to connect.')

        (options, args) = parser.parse_args()
        self.connect = options.connect

        # start marionette session
        self.m = Marionette(options.address, options.port)
        self.m.start_session()

        # list all iframes
        if options.enable_list:
            self.list_all_iframes()
        # list active iframes
        elif self.connect == None:
            self.list_active_iframes()

        # connect to App
        if self.connect == None:
            exit(0)
        else:
            # connect App
            print 'Start...'
            if self.open_app(self.connect):
                self.start_js()
            else:
                exit(-1)

    def switch_sync_async(self):
        self._is_async = not self._is_async
        self._prompt = self._async_prompt if self._is_async else self._sync_prompt
        print 'Swith to', ('Async' if self._is_async else 'Sync'), 'JS execution'

    def start_js(self):
        print 'Enter \'%s\' or Crtl+D to exit the shell.' % self._INPUT_EXIT_COMMAND
        print 'And enter \':h\' for more commands.'
        try:
            while True:
                input = raw_input(self._prompt)
                # if input is EXIT command, exit this program
                if input.lower() == self._INPUT_EXIT_COMMAND:
                    self.goodbye()
                    break

                # if input is NONE, then do nothing and keep going...
                elif input == self._INPUT_NONE:
                    continue

                # if input start with ":", it should be the command.
                elif input.startswith(self._INPUT_COMMAND_PREFIX):
                    CmdDispatcher(self, input)

                # if the postfix of input is MULTIPLE_LINE, then record this line and wait the next line until no input with MULTIPLE_LINE.
                elif input.endswith(self._INPUT_MULTIPLE_LINE):
                    input_multiple = input[:len(input) - 1] + '; '
                    while True:
                        next_input = raw_input('... ')
                        if next_input.endswith(self._INPUT_MULTIPLE_LINE):
                            input_multiple = input_multiple + next_input[:len(next_input) - 1] + '; '
                            pass
                        else:
                            input_multiple = input_multiple + next_input + '; '
                            print self.execute_script(input_multiple)
                            break

                # if input is NOT above inputs, then run marionette.execute_script(INPUT)/marionette.execute_async_script(INPUT)
                # and print return value.
                else:
                    print self.execute_script(input)

        except EOFError:
            self.goodbye()
            exit()
        except Exception as e:
            print e
            if self.open_app(-1):
                self.start_js()
        exit()

    def execute_script(self, script):
        try:
            if self._is_async:
                return self.m.execute_async_script(script)
            else:
                return self.m.execute_script(script)
        except Exception as ex:
            print str(ex.message)

    def goodbye(self):
        print 'End. Bye!!'

    def open_app(self, input):
        try:
            # connect App by ID
            app_id = int(input)
            if app_id < 0:
                print 'Connect to', self._get_system_URL()
                self.set_current_frame(self._get_system_URL())
                self.m.switch_to_frame()
            else:
                iframes = self.get_all_iframes_id_name_pair()
                print 'Connect to', iframes[str(app_id)]
                self.set_current_frame(iframes[str(app_id)])
                self.m.switch_to_frame(app_id)
            return True

        except(ValueError):
            # connect to System app
            if (input.lower() == self._INPUT_SYSTEM_APP_KEYWORD) or (input.lower() in self._get_system_URL()):
                print 'Connect to', self._get_system_URL()
                self.set_current_frame(self._get_system_URL())
                self.m.switch_to_frame()
                return True

            # connect App by substring
            iframes = self.get_all_iframes_id_name_pair()
            suitable_iframes = {}
            for k, v in iframes.items():
                if input in v:
                    suitable_iframes[k] = v
            # connect to App if there is one fit
            if len(suitable_iframes) == 1:
                target = suitable_iframes.keys()[0]
                print 'Connect to', suitable_iframes.values()[0]
                self.set_current_frame(suitable_iframes.values()[0])
                self.m.switch_to_frame(int(target))
                return True
            # exit if there are more than one app fit the query
            elif len(suitable_iframes) > 1:
                print 'There are more than one Apps fit the query string [', input, '].'
                print '{0:2s} {1:s}'.format('#', 'App URL')
                for k, v in sorted(suitable_iframes.items()):
                    print '{0:2s} {1:s}'.format(k, v)
                return False
            # exit if there is no app fit the query
            else:
                print 'There is no App fit the query string [', input, '].'
                return False

    def set_current_frame(self, frame_name):
        self._current_frame = frame_name

    def get_current_frame(self):
        return self._current_frame

    def switch_to_system_frame(self):
        self.m.switch_to_frame()

    def _get_system_URL(self):
        self.switch_to_system_frame()
        system_URL = self.m.execute_script('return document.URL')
        return system_URL

    def _get_all_iframes(self):
        self.switch_to_system_frame()
        iframes = self.m.execute_script('return document.getElementsByTagName("iframe")')
        return iframes

    def get_all_iframes_id_name_pair(self):
        iframes = self._get_all_iframes()
        result = {}
        for idx in range(0, iframes['length']):
            iframe = iframes[str(idx)]
            result[str(idx)] = iframe.get_attribute('src')
        return result

    def list_all_iframes(self):
        iframes = self._get_all_iframes()
        print '{0:2s} {1:7s} {2:s}'.format('#', 'Status', 'App URL')
        print '{0:2s} {1:7s} {2:s}'.format('-1', '', self._get_system_URL())
        for idx in range(0, iframes['length']):
            iframe = iframes[str(idx)]
            print '{0:2s} {1:7s} {2:s}'.format(str(idx), ('active' if iframe.is_displayed() else ''), iframe.get_attribute('src'))

    def list_active_iframes(self):
        iframes = self._get_all_iframes()
        print '{0:2s} {1:7s} {2:s}'.format('#', 'Status', 'App URL')
        result = {}
        for idx in range(0, iframes['length']):
            iframe = iframes[str(idx)]
            if iframe.is_displayed():
                result[str(idx)] = iframe
        for idx, iframe in result.items():
            print '{0:2s} {1:7s} {2:s}'.format(idx, ('active' if iframe.is_displayed() else ''), iframe.get_attribute('src'))

    # TODO: seems like should using Javascript to get the idx of each iframe!?
    def get_all_iframes_by_marionette(self):
        iframes = self.m.find_elements('css selector', 'iframe')
        return iframes

    def list_all_iframes_by_marionette(self):
        iframes = self.get_all_iframes_by_marionette()
        for iframe in iframes:
            print iframe.get_attribute('src')

    def list_active_iframes_by_marionette(self):
        iframes = self.get_all_iframes_by_marionette()
        result = []
        for iframe in iframes:
            if iframe.is_displayed():
                result.append(iframe)
        for iframe in result:
            print iframe.get_attribute('src')
Beispiel #18
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
  waitFor(
    function() {
      window.wrappedJSObject.LockScreen.unlock();
      waitFor(
        function() {
          finish(window.wrappedJSObject.LockScreen.locked);
        },
        function() {
          return !window.wrappedJSObject.LockScreen.locked;
        }
      );
    },
    function() {
      return !!window.wrappedJSObject.LockScreen;
    }
  );
"""

from marionette import Marionette 

marionette = Marionette('localhost', 2828)
marionette.start_session()
marionette.import_script('gaia_apps.js')
marionette.set_script_timeout(60000)

marionette.execute_script(unlock)
result = marionette.execute_async_script("GaiaApps.launchWithName('%s')" % "MozCampAsia-QualityApps")

marionette.switch_to_frame(result.get("frame"))
pdb.set_trace()
Beispiel #20
0
import SimpleHTTPServer
import SocketServer
from marionette import Marionette

m = Marionette('localhost', 2828)
m.start_session()
script = """
var request = navigator.mozApps.install('http://localhost:3000/package.manifest');
request.onsuccess = function () {
  marionetteScriptFinished('YAY');
};
request.onerror = function(e) {
marionetteScriptFinished('Boooo :( ' + this.error.name);
};"""
print m.execute_async_script(script)
# Out[69]: u'Boooo :( INVALID_MANIFEST'