示例#1
0
    async def run_all(args):
        if args.scenario != "all":
            selected_scenario = [args.scenario]
        else:
            selected_scenario = scenarii.keys()

        # this is the loop that generates all combinations of profile
        # for the current platform when "all" is selected
        res = []
        failures = 0
        for scenario in selected_scenario:
            if args.customization != "all":
                try:
                    res.append(await one_run(scenario, args.customization))
                except Exception:
                    failures += 1
                    ERROR("Something went wrong on this one.")
                    if args.strict:
                        raise
            else:
                for customization in get_customizations():
                    LOG("Customization %s" % customization)
                    try:
                        res.append(await one_run(scenario, customization))
                    except Exception:
                        failures += 1
                        ERROR("Something went wrong on this one.")
                        if args.strict:
                            raise
        return failures, [one_res for one_res in res if one_res]
示例#2
0
    async def switch(self):
        if self._mobile:
            return
        try:
            if self.handles is None:
                self.handles = await self.session.get_window_handles()
                self.current = 0
        except Exception:
            ERROR("Could not get window handles")
            return

        if self.current not in self.handles:
            ERROR("Handle %s not in current set of windows" %
                  str(self.current))
            return

        handle = self.handles[self.current]
        if self.current == len(self.handles) - 1:
            self.current = 0
        else:
            self.current += 1
        try:
            await self.session.switch_to_window(handle)
        except Exception:
            ERROR("Could not switch to handle %s" % str(handle))
示例#3
0
    async def build_profile(self, device, headless):
        scenario = self.scenario
        profile = self.env.profile
        customization_data = self.customization_data

        scenario_func = scenarii[scenario]
        if scenario in customization_data.get("scenario", {}):
            options = customization_data["scenario"][scenario]
            LOG("Loaded options for that scenario %s" % str(options))
        else:
            options = {}

        # Adding general options
        options["platform"] = self.env.target_platform

        if not self.force_new:
            try:
                custom_name = customization_data["name"]
                get_profile(profile, self.env.target_platform, scenario, custom_name)
            except ProfileNotFoundError:
                # XXX we'll use a fresh profile for now
                fresh_profile(profile, customization_data)
        else:
            fresh_profile(profile, customization_data)

        LOG("Updating profile located at %r" % profile)
        metadata = Metadata(profile)

        LOG("Starting the Gecko app...")
        self.env.prepare(logfile=self._log_filename("adb"))
        geckodriver_logs = self._log_filename("geckodriver")
        LOG("Writing geckodriver logs in %s" % geckodriver_logs)
        try:
            firefox_instance = Firefox(**self.env.get_browser_args(headless))
            with open(geckodriver_logs, "w") as glog:
                async with get_session(
                    self.env.get_geckodriver(log_file=glog), firefox_instance
                ) as session:
                    self.env.check_session(session)
                    LOG("Running the %s scenario" % scenario)
                    metadata.update(await scenario_func(session, options))
                    LOG("%s scenario done." % scenario)

        except Exception:
            ERROR("%s scenario broke!" % scenario)

        self.env.stop_browser()
        self.env.collect_profile()

        # writing metadata
        metadata.write(
            name=self.scenario,
            customization=self.customization_data["name"],
            version=self.env.get_browser_version(),
            platform=self.env.target_platform,
        )

        LOG("Profile at %s" % profile)
        LOG("Done.")
        return metadata
示例#4
0
    async def run_all(args):
        if args.scenario != "all":
            return await one_run(args.scenario, args.customization)

        # this is the loop that generates all combinations of profile
        # for the current platform when "all" is selected
        res = []
        for scenario in scenarii.keys():
            if args.customization != "all":
                try:
                    res.append(await one_run(scenario, args.customization))
                except Exception:
                    ERROR("Something went wrong on this one.")
                    if args.strict:
                        raise
            else:
                for customization in get_customizations():
                    try:
                        res.append(await one_run(scenario, customization))
                    except Exception:
                        ERROR("Something went wrong on this one.")
                        if args.strict:
                            raise
        return res
示例#5
0
 def dump_logs(self):
     LOG("Dumping Android logs")
     try:
         logcat = self.device.get_logcat()
         if logcat:
             # local path, not using posixpath
             logfile = os.path.join(self.archive, "logcat.log")
             LOG("Writing logcat at %s" % logfile)
             with open(logfile, "wb") as f:
                 for line in logcat:
                     f.write(line.encode("utf8", errors="replace") + b"\n")
         else:
             LOG("logcat came back empty")
     except Exception:
         ERROR("Could not extract the logcat")
示例#6
0
    def dump_logs(self):
        try:
            logcat = self.device.get_logcat()
        except ADBError:
            ERROR("logcat call failure")
            return

        if logcat:
            # local path, not using posixpath
            logfile = os.path.join(self.archive, "logcat.log")
            LOG("Writing logcat at %s" % logfile)
            with open(logfile, "wb") as f:
                for line in logcat:
                    f.write(line.encode("utf8") + b"\n")
        else:
            LOG("logcat came back empty")
示例#7
0
 def get_browser_version(self):
     try:
         return get_version(self.firefox)
     except Exception as e:
         ERROR("Could not get Firefox version %s" % str(e))
         return "unknown"
示例#8
0
    def prepare(self, profile, logfile):
        self._set_adb_logger(logfile)
        try:
            self.device = ADBDevice(verbose=self.verbose, logger_name="adb")
        except Exception:
            ERROR("Cannot initialize device")
            raise
        device = self.device
        self.profile = profile

        # checking that the app is installed
        if not device.is_app_installed(self.app_name):
            raise Exception("%s is not installed" % self.app_name)

        # debug flag
        LOG("Setting %s as the debug app on the phone" % self.app_name)
        device.shell("am set-debug-app --persistent %s" % self.app_name,
                     stdout_callback=LOG)

        # creating the profile on the device
        LOG("Creating the profile on the device")
        remote_test_root = posixpath.join(device.test_root, "condprof")
        remote_profile = posixpath.join(remote_test_root, "profile")
        LOG("The profile on the phone will be at %s" % remote_profile)
        device.rm(remote_test_root, force=True, recursive=True)
        device.mkdir(remote_test_root)
        device.chmod(remote_test_root, recursive=True, root=True)

        device.rm(remote_profile, force=True, recursive=True)
        LOG("Pushing %s on the phone" % self.profile)
        device.push(profile, remote_profile)
        device.chmod(remote_profile, recursive=True, root=True)
        self.profile = profile
        self.remote_profile = remote_profile

        # creating the yml file
        yml_data = {
            "args": ["-marionette", "-profile", self.remote_profile],
            "prefs": DEFAULT_PREFS,
            "env": {
                "LOG_VERBOSE": 1,
                "R_LOG_LEVEL": 6,
                "MOZ_LOG": ""
            },
        }

        yml_name = "%s-geckoview-config.yaml" % self.app_name
        yml_on_host = posixpath.join(tempfile.mkdtemp(), yml_name)
        write_yml_file(yml_on_host, yml_data)
        tmp_on_device = posixpath.join("/data", "local", "tmp")
        if not device.exists(tmp_on_device):
            raise IOError("%s does not exists on the device" % tmp_on_device)
        yml_on_device = posixpath.join(tmp_on_device, yml_name)
        try:
            device.rm(yml_on_device, force=True, recursive=True)
            device.push(yml_on_host, yml_on_device)
            device.chmod(yml_on_device, recursive=True, root=True)
        except Exception:
            LOG("could not create the yaml file on device. Permission issue?")
            raise

        # command line 'extra' args not used with geckoview apps; instead we use
        # an on-device config.yml file
        intent = "android.intent.action.VIEW"
        device.stop_application(self.app_name)
        device.launch_application(self.app_name,
                                  self.activity,
                                  intent,
                                  extras=None,
                                  url="about:blank")
        if not device.process_exist(self.app_name):
            raise Exception("Could not start %s" % self.app_name)

        LOG("Creating socket forwarding on port %d" % self.marionette_port)
        device.forward(
            local="tcp:%d" % self.marionette_port,
            remote="tcp:%d" % self.marionette_port,
        )

        # we don't have a clean way for now to check that GV or Fenix
        # is ready to handle our tests. So here we just wait 30s
        LOG("Sleeping for 30s")
        time.sleep(30)
示例#9
0
def get_profile(
    target_dir,
    platform,
    scenario,
    customization="default",
    task_id=None,
    download_cache=True,
    repo="mozilla-central",
):
    """Extract a conditioned profile in the target directory.

    If task_id is provided, will grab the profile from that task. when not
    provided (default) will grab the latest profile.
    """
    # XXX assert values
    params = {
        "platform": platform,
        "scenario": scenario,
        "customization": customization,
        "task_id": task_id,
        "repo": repo,
    }
    filename = ARTIFACT_NAME % params
    if task_id is None:
        url = TC_LINK % params + filename
    else:
        url = DIRECT_LINK % params + filename

    if not download_cache:
        download_dir = tempfile.mkdtemp()
    else:
        # using a cache dir in the user home dir
        download_dir = os.path.expanduser(CONDPROF_CACHE)
        if not os.path.exists(download_dir):
            os.makedirs(download_dir)

    downloaded_archive = os.path.join(download_dir, filename)
    retries = 0

    while retries < RETRIES:
        try:
            LOG("Getting %s" % url)
            try:
                archive = download_file(url, target=downloaded_archive)
            except ArchiveNotFound:
                raise ProfileNotFoundError(url)

            try:
                with tarfile.open(archive, "r:gz") as tar:
                    LOG("Extracting the tarball content in %s" % target_dir)
                    size = len(list(tar))
                    with progress.Bar(expected_size=size) as bar:

                        def _extract(self, *args, **kw):
                            if not TASK_CLUSTER:
                                bar.show(bar.last_progress + 1)
                            return self.old(*args, **kw)

                        tar.old = tar.extract
                        tar.extract = functools.partial(_extract, tar)
                        tar.extractall(target_dir)
            except (OSError, tarfile.ReadError) as e:
                LOG("Failed to extract the tarball")
                if download_cache and os.path.exists(archive):
                    LOG("Removing cached file to attempt a new download")
                    os.remove(archive)
                raise ProfileNotFoundError(str(e))
            finally:
                if not download_cache:
                    shutil.rmtree(download_dir)
            LOG("Success, we have a profile to work with")
            return target_dir
        except Exception:
            LOG("Failed to get the profile.")
            retries += 1
            if os.path.exists(downloaded_archive):
                try:
                    os.remove(downloaded_archive)
                except Exception:
                    ERROR("Could not remove the file")
            time.sleep(RETRY_PAUSE)

    # If we reach that point, it means all attempts failed
    ERROR("All attempt failed")
    raise ProfileNotFoundError(url)