1# This Source Code Form is subject to the terms of the Mozilla Public 2# License, v. 2.0. If a copy of the MPL was not distributed with this 3# file, You can obtain one at http://mozilla.org/MPL/2.0/. 4from __future__ import absolute_import 5 6import json 7import tempfile 8import time 9import pathlib 10 11from mozperftest.test.browsertime import add_options 12from mozperftest.system.android import _ROOT_URL 13from mozperftest.utils import ( 14 download_file, 15 get_multi_tasks_url, 16 get_revision_namespace_url, 17 install_package, 18) 19 20# We specifically select this URL because: 21# - we access Mozilla URLs in tests so any connections to Mozilla URLs may re-use 22# existing connections and have different perf characteristics. We can mostly 23# avoid this problem by using a non-Mozilla URL 24# - we authored the site so we can guarantee it doesn't change or change it if 25# needed 26# - we're not directing traffic to a site we don't own 27URL = "'https://mozilla-mobile.github.io/perf-tools/mozperftest-test-page.html'" 28 29COMMON_OPTIONS = [ 30 ("processStartTime", "true"), 31 ("firefox.disableBrowsertimeExtension", "true"), 32 ("firefox.android.intentArgument", "'-a'"), 33 ("firefox.android.intentArgument", "'android.intent.action.VIEW'"), 34 ("firefox.android.intentArgument", "'-d'"), 35 ("firefox.android.intentArgument", URL), 36] 37 38NIGHTLY_SIM_ROUTE = "mobile.v2.fenix.nightly-simulation" 39ROUTE_SUFFIX = "artifacts/public/build/{architecture}/target.apk" 40 41build_generator = None 42 43 44def before_iterations(kw): 45 global build_generator 46 47 install_list = kw.get("android_install_apk") 48 if len(install_list) == 0 or all( 49 ["fenix_nightlysim_multicommit" not in apk for apk in install_list] 50 ): 51 return 52 53 # Install gitpython 54 install_package(kw["virtualenv"], "gitpython==3.1.0") 55 import git 56 57 class _GitProgress(git.RemoteProgress): 58 def update(self, op_code, cur_count, max_count=None, message=""): 59 if message: 60 print(message) 61 62 # Setup the local fenix github repo 63 print("Cloning fenix repo...") 64 fenix_repo = git.Repo.clone_from( 65 "https://github.com/mozilla-mobile/fenix", 66 tempfile.mkdtemp(), 67 branch="master", 68 progress=_GitProgress(), 69 ) 70 71 # Get the builds to test 72 architecture = ( 73 "arm64-v8a" if "arm64_v8a" in kw.get("android_install_apk") else "armeabi-v7a" 74 ) 75 json_ = _fetch_json( 76 get_revision_namespace_url, NIGHTLY_SIM_ROUTE, day=kw["test_date"] 77 ) 78 namespaces = json_["namespaces"] 79 revisions = [namespace["name"] for namespace in namespaces] 80 81 tasks = [] 82 for revision in revisions: 83 try: 84 commit = fenix_repo.commit(revision) 85 name_rev = str(commit.name_rev) 86 if ( 87 "remotes/origin" not in name_rev 88 or "release" in name_rev 89 or "tag" in name_rev 90 ): 91 print( 92 "Commit %s is a release-branch commit, it won't be tested." 93 % revision 94 ) 95 continue 96 97 commitdate = commit.committed_date 98 except ValueError: 99 print("Commit %s is not from the Fenix master branch" % revision) 100 continue 101 102 json_ = _fetch_json( 103 get_multi_tasks_url, NIGHTLY_SIM_ROUTE, revision, day=kw["test_date"] 104 ) 105 for task in json_["tasks"]: 106 route = task["namespace"] 107 task_architecture = route.split(".")[-1] 108 if task_architecture == architecture: 109 tasks.append( 110 { 111 "timestamp": commitdate, 112 "revision": revision, 113 "route": route, 114 "route_suffix": ROUTE_SUFFIX.format( 115 architecture=task_architecture 116 ), 117 } 118 ) 119 120 # Set the number of test-iterations to the number of builds 121 kw["test_iterations"] = len(tasks) 122 123 def _build_iterator(): 124 for task in tasks: 125 revision = task["revision"] 126 timestamp = task["timestamp"] 127 128 humandate = time.ctime(int(timestamp)) 129 print(f"Testing revision {revision} from {humandate}") 130 131 download_url = f'{_ROOT_URL}{task["route"]}/{task["route_suffix"]}' 132 yield revision, timestamp, [download_url] 133 134 build_generator = _build_iterator() 135 136 return kw 137 138 139def _fetch_json(get_url_function, *args, **kwargs): 140 build_url = get_url_function(*args, **kwargs) 141 tmpfile = pathlib.Path(tempfile.mkdtemp(), "temp.json") 142 download_file(build_url, tmpfile) 143 144 with tmpfile.open() as f: 145 return json.load(f) 146 147 148def before_runs(env, **kw): 149 global build_generator 150 151 add_options(env, COMMON_OPTIONS) 152 if build_generator: 153 revision, timestamp, build = next(build_generator) 154 env.set_arg("android-install-apk", build) 155 env.set_arg("perfherder-prefix", revision) 156 env.set_arg("perfherder-timestamp", timestamp) 157