summaryrefslogtreecommitdiffstats
path: root/testing/condprofile/condprof/runner.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testing/condprofile/condprof/runner.py212
1 files changed, 212 insertions, 0 deletions
diff --git a/testing/condprofile/condprof/runner.py b/testing/condprofile/condprof/runner.py
new file mode 100644
index 0000000000..0e9b7b54e8
--- /dev/null
+++ b/testing/condprofile/condprof/runner.py
@@ -0,0 +1,212 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+""" Script that launches profiles creation.
+"""
+import os
+import shutil
+import asyncio
+
+import mozversion
+
+from condprof.creator import ProfileCreator
+from condprof.desktop import DesktopEnv
+from condprof.android import AndroidEnv
+from condprof.changelog import Changelog
+from condprof.scenarii import scenarii
+from condprof.util import logger, get_current_platform, extract_from_dmg
+from condprof.customization import get_customizations, find_customization
+from condprof.client import read_changelog, ProfileNotFoundError
+
+
+class Runner:
+ def __init__(
+ self,
+ profile,
+ firefox,
+ geckodriver,
+ archive,
+ device_name,
+ strict,
+ force_new,
+ visible,
+ skip_logs=False,
+ remote_test_root="/sdcard/test_root/",
+ ):
+ self.force_new = force_new
+ self.profile = profile
+ self.geckodriver = geckodriver
+ self.archive = archive
+ self.device_name = device_name
+ self.strict = strict
+ self.visible = visible
+ self.skip_logs = skip_logs
+ self.remote_test_root = remote_test_root
+ self.env = {}
+ # unpacking a dmg
+ # XXX do something similar if we get an apk (but later)
+ # XXX we want to do
+ # adb install -r target.apk
+ # and get the installed app name
+ if firefox is not None and firefox.endswith("dmg"):
+ target = os.path.join(os.path.dirname(firefox), "firefox.app")
+ extract_from_dmg(firefox, target)
+ firefox = os.path.join(target, "Contents", "MacOS", "firefox")
+ self.firefox = firefox
+ self.android = self.firefox is not None and self.firefox.startswith(
+ "org.mozilla"
+ )
+
+ def prepare(self, scenario, customization):
+ self.scenario = scenario
+ self.customization = customization
+
+ # early checks to avoid extra work
+ if self.customization != "all":
+ if find_customization(self.customization) is None:
+ raise IOError("Cannot find customization %r" % self.customization)
+
+ if self.scenario != "all" and self.scenario not in scenarii:
+ raise IOError("Cannot find scenario %r" % self.scenario)
+
+ if not self.android and self.firefox is not None:
+ logger.info("Verifying Desktop Firefox binary")
+ # we want to verify we do have a firefox binary
+ # XXX so lame
+ if not os.path.exists(self.firefox):
+ if "MOZ_FETCHES_DIR" in os.environ:
+ target = os.path.join(os.environ["MOZ_FETCHES_DIR"], self.firefox)
+ if os.path.exists(target):
+ self.firefox = target
+
+ if not os.path.exists(self.firefox):
+ raise IOError("Cannot find %s" % self.firefox)
+
+ mozversion.get_version(self.firefox)
+
+ logger.info(os.environ)
+ if self.archive:
+ self.archive = os.path.abspath(self.archive)
+ logger.info("Archives directory is %s" % self.archive)
+ if not os.path.exists(self.archive):
+ os.makedirs(self.archive, exist_ok=True)
+
+ logger.info("Verifying Geckodriver binary presence")
+ if shutil.which(self.geckodriver) is None and not os.path.exists(
+ self.geckodriver
+ ):
+ raise IOError("Cannot find %s" % self.geckodriver)
+
+ if not self.skip_logs:
+ try:
+ if self.android:
+ plat = "%s-%s" % (
+ self.device_name,
+ self.firefox.split("org.mozilla.")[-1],
+ )
+ else:
+ plat = get_current_platform()
+ self.changelog = read_changelog(plat)
+ logger.info("Got the changelog from TaskCluster")
+ except ProfileNotFoundError:
+ logger.info("changelog not found on TaskCluster, creating a local one.")
+ self.changelog = Changelog(self.archive)
+ else:
+ self.changelog = []
+
+ def _create_env(self):
+ if self.android:
+ klass = AndroidEnv
+ else:
+ klass = DesktopEnv
+
+ return klass(
+ self.profile, self.firefox, self.geckodriver, self.archive, self.device_name
+ )
+
+ def display_error(self, scenario, customization):
+ logger.error("%s x %s failed." % (scenario, customization), exc_info=True)
+ # TODO: this might avoid the exceptions that slip through in automation
+ # if self.strict:
+ # raise
+
+ async def one_run(self, scenario, customization):
+ """Runs one single conditioned profile.
+
+ Create an instance of the environment and run the ProfileCreator.
+ """
+ self.env = self._create_env()
+ return await ProfileCreator(
+ scenario,
+ customization,
+ self.archive,
+ self.changelog,
+ self.force_new,
+ self.env,
+ skip_logs=self.skip_logs,
+ remote_test_root=self.remote_test_root,
+ ).run(not self.visible)
+
+ async def run_all(self):
+ """Runs the conditioned profile builders"""
+ if self.scenario != "all":
+ selected_scenario = [self.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 self.customization != "all":
+ try:
+ res.append(await self.one_run(scenario, self.customization))
+ except Exception:
+ failures += 1
+ self.display_error(scenario, self.customization)
+ else:
+ for customization in get_customizations():
+ logger.info("Customization %s" % customization)
+ try:
+ res.append(await self.one_run(scenario, customization))
+ except Exception:
+ failures += 1
+ self.display_error(scenario, customization)
+
+ return failures, [one_res for one_res in res if one_res]
+
+ def save(self):
+ self.changelog.save(self.archive)
+
+
+def run(
+ archive,
+ firefox=None,
+ scenario="all",
+ profile=None,
+ customization="all",
+ visible=False,
+ archives_dir="/tmp/archives",
+ force_new=False,
+ strict=True,
+ geckodriver="geckodriver",
+ device_name=None,
+):
+ runner = Runner(
+ profile, firefox, geckodriver, archive, device_name, strict, force_new, visible
+ )
+
+ runner.prepare(scenario, customization)
+ loop = asyncio.get_event_loop()
+
+ try:
+ failures, results = loop.run_until_complete(runner.run_all())
+ logger.info("Saving changelog in %s" % archive)
+ runner.save()
+ if failures > 0:
+ raise Exception("At least one scenario failed")
+ except Exception as e:
+ raise e
+ finally:
+ loop.close()