class TestConsoleLogCapture():
    def setup(self):
        try:
            self.client = Marionette(host='localhost', port=2828)
            self.client.start_session()
            self.client.set_pref('general.warnOnAboutConfig', False)
        except:
            sys.exit("Could not find Firefox browser running")

    def test_push_notification_received(self):
        self.client.navigate(
            "https://people.mozilla.org/~ewong2/push-notification-test/")

        unregister_button = self.client.find_element(By.ID, "unreg_btn")
        if unregister_button.is_displayed() == True:
            unregister_button.click()
            Wait(self.client, timeout=5, interval=1).until(
                expected.element_not_displayed(By.ID, "unreg_btn"))

        Wait(self.client).until(expected.element_displayed(By.ID, "reg_btn"))
        self.client.find_element(By.ID, "reg_btn").click()
        Wait(self.client).until(
            expected.element_displayed(By.ID, "subscribe_btn"))
        self.client.find_element(By.ID, "subscribe_btn").click()
        Wait(self.client).until(expected.element_displayed(By.ID, "doXhr_btn"))
        self.client.find_element(By.ID, "doXhr_btn").click()

        result = self.web_console_filter_for_string("Received a push message")
        assert result == 1

    def web_console_filter_for_string(self, console_string=None):
        self.client.set_context(self.client.CONTEXT_CHROME)

        handles = self.client.window_handles
        chrome_handles = self.client.chrome_window_handles
        browser_handle = self.client.current_chrome_window_handle
        notifications = 0
        for handle in chrome_handles:
            if handle != browser_handle:
                console_handle = handle
                self.client.switch_to_window(console_handle)
                time.sleep(1)
                results = self.client.find_elements(By.CLASS_NAME,
                                                    "console-string")
                for result in results:
                    if console_string in result.text:
                        notifications = notifications + 1
        self.client.find_element(By.CLASS_NAME,
                                 "webconsole-clear-console-button").click()
        return notifications

    def tear_down(self):
        self.client.close()
class TestConsoleLogCapture():
    def setup(self):
        try:
            self.client = Marionette(host='localhost', port=2828)
            self.client.start_session()
            self.client.set_pref('general.warnOnAboutConfig', False)
        except:
            sys.exit("Could not find Firefox browser running")

    def test_push_notification_received(self):
        self.client.navigate("https://people.mozilla.org/~ewong2/push-notification-test/")

        unregister_button = self.client.find_element(By.ID, "unreg_btn")
        if unregister_button.is_displayed() == True:
            unregister_button.click()
            Wait(self.client, timeout=5, interval=1).until(expected.element_not_displayed(By.ID, "unreg_btn"))

        Wait(self.client).until(expected.element_displayed(By.ID, "reg_btn"))
        self.client.find_element(By.ID, "reg_btn").click()
        Wait(self.client).until(expected.element_displayed(By.ID, "subscribe_btn"))
        self.client.find_element(By.ID, "subscribe_btn").click()
        Wait(self.client).until(expected.element_displayed(By.ID, "doXhr_btn"))
        self.client.find_element(By.ID, "doXhr_btn").click()

        result = self.web_console_filter_for_string("Received a push message")
        assert result == 1

    def web_console_filter_for_string(self, console_string=None):
        self.client.set_context(self.client.CONTEXT_CHROME)

        handles = self.client.window_handles
        chrome_handles = self.client.chrome_window_handles
        browser_handle = self.client.current_chrome_window_handle
        notifications = 0
        for handle in chrome_handles:
            if handle != browser_handle:
                console_handle = handle
                self.client.switch_to_window(console_handle)
                time.sleep(1)
                results = self.client.find_elements(By.CLASS_NAME, "console-string")
                for result in results:
                    if console_string in result.text:
                        notifications = notifications + 1
        self.client.find_element(By.CLASS_NAME, "webconsole-clear-console-button").click()
        return notifications


    def tear_down(self):
        self.client.close()
Example #3
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')
Example #4
0
    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())
    assert(m.find_element(HTMLElement.ID, 'id3').get_attribute('value') == server.TEST_GET_VALUE)
    assert(m.delete_session())
Example #5
0
 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').is_selected())
 assert (m.find_element(HTMLElement.ID,
class current_frame():
    
    filename_screenshot = ""
    filename_htmldump   = ""
    
    def main(self, LOGDIR):
        #
        # The first variable is the log directory.
        #
        ucount  = 0
        self.marionette = Marionette(host='localhost', port=2828)  
        self.marionette.start_session()
        self.marionette.set_search_timeout(1000)
        
        #
        # Now loop through all the iframes, gathering details about each one.
        #
        print ""
        print "Iframe for 'top level' () ..."
        self.filename_screenshot = LOGDIR + "top_level" + ".png"
        self.filename_htmldump   = LOGDIR + "top_level" + ".html"
        self.marionette.switch_to_frame()
        self.record_frame()
        
        frames = self.marionette.find_elements("tag name", "iframe")
        for fnum in range (0, len(frames)):
          
            #
            # App name is usually in the "src" attribute, so it's worth a shot..
            #
            frame_src = frames[fnum].get_attribute("src")
              
            if frame_src != "":
                startpos = frame_src.index('/') + 2
                stoppos  = frame_src.index('.')
                appname  = frame_src[startpos:stoppos]
                filename = appname
            else:
                ucount = ucount + 1
                appname  = "(unknown)"
                filename = "unknown_" + str(ucount)
            
            #
            # Because we call this script sometimes when we hit a Marionette issue,
            # these filenames may already exist (and we'd overwrite them!), so
            # add 'DEBUG_' to the start of the filename.
            #
            filename = "DEBUG_" + filename
                 
            filename_details         = LOGDIR + filename + "_iframe_details.txt"
            self.filename_screenshot = LOGDIR + filename + ".png"
            self.filename_htmldump   = LOGDIR + filename + ".html"
            
            #
            # This iframe gives me problems sometimes, so I'm ignoring it for now.
            #
            if appname == "costcontrol":
                continue
            
            print ""
            print "Iframe for app \"" + appname + "\" ..."
        
            #
            # Record the iframe details (pretty verbose, but 'execute_script' 
            # wasn't letting me use 'for' loops in js for some reason).
            #
            print "    |_ iframe details saved to : " + filename_details
            f = open(filename_details, 'w')
            f.write("Attributes for this iframe ...\n")
            num_attribs = self.marionette.execute_script("return document.getElementsByTagName('iframe')[" + str(fnum) + "].attributes.length;")
            for i in range(0,num_attribs):
                attrib_name  = self.marionette.execute_script("return document.getElementsByTagName('iframe')[" + str(fnum) + "].attributes[" + str(i) + "].nodeName;")
                attrib_value = self.marionette.execute_script("return document.getElementsByTagName('iframe')[" + str(fnum) + "].attributes[" + str(i) + "].nodeValue;")
        
                f.write("    |_ " + attrib_name.ljust(20) + ": \"" + attrib_value + "\"\n")   
            f.close()
            
            #
            # Switch to this frame.
            #
            self.marionette.switch_to_frame(fnum)
                   
            self.record_frame()
         
            self.marionette.switch_to_frame()


    def record_frame(self):
        #
        # Take the screenshot and save it to the file.
        #
        print "    |_ screenshot saved to     : " + self.filename_screenshot
        screenshot = self.marionette.screenshot()[22:]
        with open(self.filename_screenshot, 'w') as f:
            f.write(base64.decodestring(screenshot))
        f.close()
              
        #
        # Take the html dump and save it to the file.
        #
        print "    |_ html dump saved to      : " + self.filename_htmldump
        f = open(self.filename_htmldump, 'w')
        f.write(self.marionette.page_source.encode('ascii', 'ignore') )
        f.close()
Example #7
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
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
Example #9
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')