brizental pushed to branch main at The Tor Project / Applications / tor-browser-bundle-testsuite
Commits:
-
ce7fa79b
by Beatriz Rizental at 2026-09-16T14:32:16-03:00
-
03eca1fb
by Beatriz Rizental at 2026-09-16T16:09:52-03:00
8 changed files:
- .gitlab-ci.yml
- .gitlab/_base.yml
- .gitlab/_inputs.yml
- .gitlab/scripts/before_script.py
- .gitlab/test_marionette.yml
- + .gitlab/test_xpcshell.yml
- config/tb-build-06.torproject.org
- tools/trigger-test-pipeline.py
Changes:
| ... | ... | @@ -3,6 +3,7 @@ spec: |
| 3 | 3 | - local: '.gitlab/_inputs.yml'
|
| 4 | 4 | ---
|
| 5 | 5 | stages:
|
| 6 | + - test-xpcshell
|
|
| 6 | 7 | - test-marionette
|
| 7 | 8 | |
| 8 | 9 | default:
|
| ... | ... | @@ -17,7 +18,7 @@ include: |
| 17 | 18 | - local: '.gitlab/_base.yml'
|
| 18 | 19 | inputs:
|
| 19 | 20 | mozharness_url: $[[ inputs.mozharness_url ]]
|
| 20 | - tag: $[[ inputs.tag ]]
|
|
| 21 | + tags: $[[ inputs.tags ]]
|
|
| 21 | 22 | android_x86_64_installer_url: $[[ inputs.android_x86_64_installer_url ]]
|
| 22 | 23 | android_x86_64_package_name: $[[ inputs.android_x86_64_package_name ]]
|
| 23 | 24 | android_x86_64_artifacts_url: $[[ inputs.android_x86_64_artifacts_url ]]
|
| ... | ... | @@ -31,4 +32,5 @@ include: |
| 31 | 32 | windows_x86_64_installer_url: $[[ inputs.windows_x86_64_installer_url ]]
|
| 32 | 33 | windows_x86_64_artifacts_url: $[[ inputs.windows_x86_64_artifacts_url ]]
|
| 33 | 34 | windows_x86_64_sha256sums_url: $[[ inputs.windows_x86_64_sha256sums_url ]]
|
| 35 | + - local: '.gitlab/test_xpcshell.yml'
|
|
| 34 | 36 | - local: '.gitlab/test_marionette.yml' |
| ... | ... | @@ -4,9 +4,10 @@ spec: |
| 4 | 4 | ---
|
| 5 | 5 | variables:
|
| 6 | 6 | MOZHARNESS_URL: "$[[ inputs.mozharness_url ]]"
|
| 7 | - TAG: "$[[ inputs.tag ]]"
|
|
| 7 | + TAGS: "$[[ inputs.tags ]]"
|
|
| 8 | 8 | |
| 9 | 9 | .common:
|
| 10 | + allow_failure: true
|
|
| 10 | 11 | before_script:
|
| 11 | 12 | - python3 .gitlab/scripts/before_script.py
|
| 12 | 13 | |
| ... | ... | @@ -16,6 +17,10 @@ variables: |
| 16 | 17 | .debian-x86_64:
|
| 17 | 18 | extends: .common
|
| 18 | 19 | |
| 20 | + before_script:
|
|
| 21 | + - Xvfb :99 -screen 0 1280x1024x24 >/dev/null 2>&1 &
|
|
| 22 | + - !reference [.common, before_script]
|
|
| 23 | + |
|
| 19 | 24 | tags:
|
| 20 | 25 | - debian-trixie-x86_64
|
| 21 | 26 | |
| ... | ... | @@ -25,9 +30,11 @@ variables: |
| 25 | 30 | - when: never
|
| 26 | 31 | |
| 27 | 32 | variables:
|
| 33 | + DISPLAY: ":99"
|
|
| 28 | 34 | MOZ_FETCHES_DIR: "/home/gitlab-runner/fetches"
|
| 29 | 35 | MINIDUMP_STACKWALK_URL: "https://github.com/rust-minidump/rust-minidump/releases/download/v0.26.1/minidump-stackwalk-x86_64-unknown-linux-gnu.tar.xz"
|
| 30 | 36 | MINIDUMP_STACKWALK_SHA256: "f789997f086dab6e46c46ab4560fc28676124613770ddac3b89a6e2e0e4963d8"
|
| 37 | + NODEJS_PATH: "/home/gitlab-runner/.nvm/versions/node/v22.16.0/bin/node"
|
|
| 31 | 38 | INSTALLER_URL: "$[[ inputs.debian_x86_64_installer_url ]]"
|
| 32 | 39 | ARTIFACTS_URL: "$[[ inputs.debian_x86_64_artifacts_url ]]"
|
| 33 | 40 | SHA256SUMS_URL: "$[[ inputs.debian_x86_64_sha256sums_url ]]"
|
| ... | ... | @@ -35,6 +42,11 @@ variables: |
| 35 | 42 | .macos-x86_64:
|
| 36 | 43 | extends: .common
|
| 37 | 44 | |
| 45 | + # Overwrite just so we can change $PATH
|
|
| 46 | + before_script:
|
|
| 47 | + - export PATH="/usr/local/bin:$PATH"
|
|
| 48 | + - !reference [.common, before_script]
|
|
| 49 | + |
|
| 38 | 50 | tags:
|
| 39 | 51 | - macos-sonoma-x86_64
|
| 40 | 52 | |
| ... | ... | @@ -47,6 +59,7 @@ variables: |
| 47 | 59 | MOZ_FETCHES_DIR: "/Users/gitlab-runner/fetches"
|
| 48 | 60 | MINIDUMP_STACKWALK_URL: "https://github.com/rust-minidump/rust-minidump/releases/download/v0.26.1/minidump-stackwalk-x86_64-apple-darwin.tar.xz"
|
| 49 | 61 | MINIDUMP_STACKWALK_SHA256: "7a3e274a09bc35ccc35e9d3dcd60e738ab14e54ea3306be94a4a8dedaf7a468d"
|
| 62 | + NODEJS_PATH: "/Users/gitlab-runner/.nvm/versions/node/v22.16.0/bin/node"
|
|
| 50 | 63 | INSTALLER_URL: "$[[ inputs.macos_x86_64_installer_url ]]"
|
| 51 | 64 | ARTIFACTS_URL: "$[[ inputs.macos_x86_64_artifacts_url ]]"
|
| 52 | 65 | SHA256SUMS_URL: "$[[ inputs.macos_x86_64_sha256sums_url ]]"
|
| ... | ... | @@ -66,6 +79,7 @@ variables: |
| 66 | 79 | MOZ_FETCHES_DIR: 'C:\windoes\fetches'
|
| 67 | 80 | MINIDUMP_STACKWALK_URL: 'https://github.com/rust-minidump/rust-minidump/releases/download/v0.26.1/minidump-stackwalk-x86_64-pc-windows-msvc.zip'
|
| 68 | 81 | MINIDUMP_STACKWALK_SHA256: "dc6da411047ef15b784bffe0f9bf7ecb9221186c4c8fd655e3d8a3fbba0a9c61"
|
| 82 | + NODEJS_PATH: 'C:\Program Files\nodejs\node.exe'
|
|
| 69 | 83 | INSTALLER_URL: "$[[ inputs.windows_x86_64_installer_url ]]"
|
| 70 | 84 | ARTIFACTS_URL: "$[[ inputs.windows_x86_64_artifacts_url ]]"
|
| 71 | 85 | SHA256SUMS_URL: "$[[ inputs.windows_x86_64_sha256sums_url ]]"
|
| ... | ... | @@ -3,10 +3,10 @@ inputs: |
| 3 | 3 | type: string
|
| 4 | 4 | default: ""
|
| 5 | 5 | description: "Location of the mozharness.zip archive"
|
| 6 | - tag:
|
|
| 6 | + tags:
|
|
| 7 | 7 | type: string
|
| 8 | 8 | default: ""
|
| 9 | - description: "Tag used to filter tests"
|
|
| 9 | + description: "Space-separated --tag flags (e.g. '--tag foo --tag bar'). Will run all tests if not provided"
|
|
| 10 | 10 | |
| 11 | 11 | android_x86_64_installer_url:
|
| 12 | 12 | type: string
|
| 1 | 1 | import hashlib
|
| 2 | 2 | import os
|
| 3 | +import platform
|
|
| 3 | 4 | import shutil
|
| 4 | 5 | import subprocess
|
| 5 | 6 | import time
|
| ... | ... | @@ -32,12 +33,17 @@ def download_file(url: str, dest: Path, sha256: str = "") -> None: |
| 32 | 33 | |
| 33 | 34 | |
| 34 | 35 | def extract_tar(tar_path: Path, dest_dir: Path) -> None:
|
| 35 | - subprocess.run(
|
|
| 36 | + result = subprocess.run(
|
|
| 36 | 37 | # --strip-components=1: all the archives we fetch have contents nested inside a
|
| 37 | 38 | # top-level directory rather than at the root, so we strip it on extraction.
|
| 38 | - ["tar", "-xf", str(tar_path), "-C", str(dest_dir), "--strip-components=1"],
|
|
| 39 | - check=True,
|
|
| 39 | + #
|
|
| 40 | + # NOTE: The `v` flag is _required_ for tar to work on MacOS ¯\_(ツ)_/¯
|
|
| 41 | + ["tar", f"-x{'v' if platform.system() == 'Darwin' else ''}f", str(tar_path), "-C", str(dest_dir), "--strip-components=1"],
|
|
| 42 | + stderr=subprocess.PIPE,
|
|
| 43 | + text=True,
|
|
| 40 | 44 | )
|
| 45 | + if result.returncode != 0:
|
|
| 46 | + raise RuntimeError(f"tar failed (exit {result.returncode}):\n{result.stderr}")
|
|
| 41 | 47 | |
| 42 | 48 | |
| 43 | 49 | def check_sha256sums_url(sha256sums_url: str) -> None:
|
| ... | ... | @@ -159,6 +165,22 @@ def setup_android_sdk(moz_fetches_dir: str) -> None: |
| 159 | 165 | print(f"Moved AVD -> {android_device_dir / 'avd'}")
|
| 160 | 166 | |
| 161 | 167 | |
| 168 | + |
|
| 169 | +def download_hostutils(moz_fetches_dir: str) -> None:
|
|
| 170 | + # Stable mirror of https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/gecko.cache.level-3.toolchains.v3.linux64-hostutils.latest/artifacts/public%2Fbuild%2Fhostutils.tar.zst
|
|
| 171 | + HOSTUTILS_URL = "https://build-sources.tbb.torproject.org/hostutils.tar.zst"
|
|
| 172 | + HOSTUTILS_SHA256 = (
|
|
| 173 | + "90ff9390181d7dc015c882f11e11800ef03be39f003c29b22bda01ad21c04a9e"
|
|
| 174 | + )
|
|
| 175 | + |
|
| 176 | + hostutils_dir = Path(moz_fetches_dir) / "hostutils"
|
|
| 177 | + hostutils_dir.mkdir(parents=True, exist_ok=True)
|
|
| 178 | + |
|
| 179 | + tar_zst_path = Path("hostutils.tar.zst")
|
|
| 180 | + download_file(HOSTUTILS_URL, tar_zst_path, HOSTUTILS_SHA256)
|
|
| 181 | + extract_tar(tar_zst_path, hostutils_dir)
|
|
| 182 | + |
|
| 183 | + |
|
| 162 | 184 | def before_script(
|
| 163 | 185 | mozharness_url: str,
|
| 164 | 186 | minidump_stackwalk_url: str,
|
| ... | ... | @@ -175,6 +197,7 @@ def before_script( |
| 175 | 197 | |
| 176 | 198 | if setup_android:
|
| 177 | 199 | setup_android_sdk(moz_fetches_dir)
|
| 200 | + download_hostutils(moz_fetches_dir)
|
|
| 178 | 201 | |
| 179 | 202 | |
| 180 | 203 | if __name__ == "__main__":
|
| 1 | -.marionette-desktop:
|
|
| 1 | +debian-x86_64_marionette:
|
|
| 2 | + extends: .debian-x86_64
|
|
| 2 | 3 | stage: test-marionette
|
| 3 | 4 | script:
|
| 4 | 5 | - >
|
| ... | ... | @@ -6,23 +7,32 @@ |
| 6 | 7 | --config-file "$(pwd)/mozharness/configs/marionette/prod_config.py"
|
| 7 | 8 | --installer-url "$INSTALLER_URL"
|
| 8 | 9 | --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
| 9 | - --tag "$TAG"
|
|
| 10 | 10 | --headless
|
| 11 | - |
|
| 12 | -debian-x86_64_marionette:
|
|
| 13 | - extends:
|
|
| 14 | - - .debian-x86_64
|
|
| 15 | - - .marionette-desktop
|
|
| 11 | + $TAGS
|
|
| 16 | 12 | |
| 17 | 13 | macos-x86_64_marionette:
|
| 18 | - extends:
|
|
| 19 | - - .macos-x86_64
|
|
| 20 | - - .marionette-desktop
|
|
| 14 | + extends: .macos-x86_64
|
|
| 15 | + stage: test-marionette
|
|
| 16 | + script:
|
|
| 17 | + - >
|
|
| 18 | + python3 "$(pwd)/mozharness/scripts/marionette.py"
|
|
| 19 | + --config-file "$(pwd)/mozharness/configs/marionette/prod_config.py"
|
|
| 20 | + --installer-url "$INSTALLER_URL"
|
|
| 21 | + --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
|
| 22 | + --headless
|
|
| 23 | + $TAGS
|
|
| 21 | 24 | |
| 22 | 25 | windows-x86_64_marionette:
|
| 23 | - extends:
|
|
| 24 | - - .windows-x86_64
|
|
| 25 | - - .marionette-desktop
|
|
| 26 | + extends: .windows-x86_64
|
|
| 27 | + stage: test-marionette
|
|
| 28 | + script:
|
|
| 29 | + - >
|
|
| 30 | + python3 "$(pwd)/mozharness/scripts/marionette.py"
|
|
| 31 | + --config-file "$(pwd)/mozharness/configs/marionette/prod_config.py"
|
|
| 32 | + --installer-url "$INSTALLER_URL"
|
|
| 33 | + --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
|
| 34 | + --headless
|
|
| 35 | + ($env:TAGS -split ' ')
|
|
| 26 | 36 | |
| 27 | 37 | android-x86_64_marionette:
|
| 28 | 38 | extends: .android-x86_64
|
| ... | ... | @@ -36,4 +46,4 @@ android-x86_64_marionette: |
| 36 | 46 | --installer-url "$INSTALLER_URL"
|
| 37 | 47 | --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
| 38 | 48 | --package-name "$PACKAGE_NAME"
|
| 39 | - --tag "$TAG" |
|
| 49 | + $TAGS |
| 1 | +debian-x86_64_xpcshell:
|
|
| 2 | + extends: .debian-x86_64
|
|
| 3 | + stage: test-xpcshell
|
|
| 4 | + script:
|
|
| 5 | + - >
|
|
| 6 | + python3 "$(pwd)/mozharness/scripts/desktop_unittest.py"
|
|
| 7 | + --config-file "$(pwd)/mozharness/configs/unittests/linux_unittest.py"
|
|
| 8 | + --xpcshell-suite xpcshell
|
|
| 9 | + --installer-url "$INSTALLER_URL"
|
|
| 10 | + --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
|
| 11 | + $TAGS
|
|
| 12 | + |
|
| 13 | +macos-x86_64_xpcshell:
|
|
| 14 | + extends: .macos-x86_64
|
|
| 15 | + stage: test-xpcshell
|
|
| 16 | + script:
|
|
| 17 | + - >
|
|
| 18 | + python3 "$(pwd)/mozharness/scripts/desktop_unittest.py"
|
|
| 19 | + --config-file "$(pwd)/mozharness/configs/unittests/mac_unittest.py"
|
|
| 20 | + --xpcshell-suite xpcshell
|
|
| 21 | + --installer-url "$INSTALLER_URL"
|
|
| 22 | + --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
|
| 23 | + $TAGS
|
|
| 24 | + |
|
| 25 | +windows-x86_64_xpcshell:
|
|
| 26 | + extends: .windows-x86_64
|
|
| 27 | + stage: test-xpcshell
|
|
| 28 | + script:
|
|
| 29 | + - >
|
|
| 30 | + python3 "$(pwd)/mozharness/scripts/desktop_unittest.py"
|
|
| 31 | + --config-file "$(pwd)/mozharness/configs/unittests/win_unittest.py"
|
|
| 32 | + --xpcshell-suite xpcshell
|
|
| 33 | + --installer-url "$INSTALLER_URL"
|
|
| 34 | + --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
|
| 35 | + --pip-index
|
|
| 36 | + ($env:TAGS -split ' ')
|
|
| 37 | + |
|
| 38 | +android-x86_64_xpcshell:
|
|
| 39 | + extends: .android-x86_64
|
|
| 40 | + stage: test-xpcshell
|
|
| 41 | + script:
|
|
| 42 | + - >
|
|
| 43 | + python3 "$(pwd)/mozharness/scripts/android_emulator_unittest.py"
|
|
| 44 | + --config-file "$(pwd)/mozharness/configs/android/android_common.py"
|
|
| 45 | + --config-file "$(pwd)/mozharness/configs/android/android14-x86_64.py"
|
|
| 46 | + --test-suite=xpcshell
|
|
| 47 | + --installer-url "$ARTIFACTS_URL/test_runner.apk"
|
|
| 48 | + --test-packages-url "$ARTIFACTS_URL/target.test_packages.json"
|
|
| 49 | + --package-name "$PACKAGE_NAME"
|
|
| 50 | + $TAGS |
| ... | ... | @@ -37,13 +37,13 @@ my $test_post = sub { |
| 37 | 37 | return unless $test->{results} && $test->{results}{success};
|
| 38 | 38 | return unless $test->{publish_dir};
|
| 39 | 39 | |
| 40 | - my $tag = $test->{name} =~ /^torbrowser/ ? 'tor' : 'mullvad-browser';
|
|
| 40 | + my $browser_tag = $test->{name} =~ /^torbrowser/ ? 'tor' : 'mullvad-browser';
|
|
| 41 | 41 | my ($stdout, $stderr, $success) = capture_exec(
|
| 42 | 42 | 'python3', "$FindBin::Bin/tools/trigger-test-pipeline.py",
|
| 43 | 43 | '--step-name', $test->{name},
|
| 44 | 44 | '--publish-url', $publish_url,
|
| 45 | 45 | '--publish-dir', $test->{publish_dir},
|
| 46 | - '--tag', $tag,
|
|
| 46 | + '--tags', "$browser_tag,base-browser",
|
|
| 47 | 47 | );
|
| 48 | 48 | write_file(
|
| 49 | 49 | "$tbbinfos->{'results-dir'}/$test->{name}.trigger-test-pipeline.stderr.txt",
|
| ... | ... | @@ -35,6 +35,13 @@ def setup_logging() -> None: |
| 35 | 35 | )
|
| 36 | 36 | |
| 37 | 37 | |
| 38 | +def comma_separated_list(value):
|
|
| 39 | + items = [item.strip() for item in value.split(",") if item.strip()]
|
|
| 40 | + if not items:
|
|
| 41 | + raise argparse.ArgumentTypeError("must provide at least one tag")
|
|
| 42 | + return items
|
|
| 43 | + |
|
| 44 | + |
|
| 38 | 45 | def parse_args() -> argparse.Namespace:
|
| 39 | 46 | parser = argparse.ArgumentParser(
|
| 40 | 47 | description="Post-build trigger hook for triggering GitLab CI pipelines."
|
| ... | ... | @@ -59,9 +66,10 @@ def parse_args() -> argparse.Namespace: |
| 59 | 66 | help="Subdirectory within the publish URL where build artifacts are located.",
|
| 60 | 67 | )
|
| 61 | 68 | parser.add_argument(
|
| 62 | - "--tag",
|
|
| 69 | + "--tags",
|
|
| 63 | 70 | required=False,
|
| 64 | - help="Tag used to filter tests.",
|
|
| 71 | + type=comma_separated_list,
|
|
| 72 | + help="Comma separated list of tags used to filter tests. Will run all tests if not provided",
|
|
| 65 | 73 | )
|
| 66 | 74 | parser.add_argument(
|
| 67 | 75 | "--dry-run",
|
| ... | ... | @@ -71,7 +79,7 @@ def parse_args() -> argparse.Namespace: |
| 71 | 79 | return parser.parse_args()
|
| 72 | 80 | |
| 73 | 81 | |
| 74 | -def build_inputs(step_name: str, publish_url: str, publish_dir: str, tag: str) -> dict[str, str] | None:
|
|
| 82 | +def build_inputs(step_name: str, publish_url: str, publish_dir: str, tags: list[str] | None) -> dict[str, str] | None:
|
|
| 75 | 83 | # Add the architecture as padding, to address the macos case which doesn't
|
| 76 | 84 | # have architecture in the step name since it is a universal build.
|
| 77 | 85 | browser, channel, platform, architecture = (step_name.split("-") + ["x86_64"])[:4]
|
| ... | ... | @@ -116,8 +124,8 @@ def build_inputs(step_name: str, publish_url: str, publish_dir: str, tag: str) - |
| 116 | 124 | if platform == "android":
|
| 117 | 125 | inputs[f"{input_prefix}_package_name"] = f"org.torproject.{browser}_{channel}"
|
| 118 | 126 | |
| 119 | - if tag:
|
|
| 120 | - inputs["tag"] = tag
|
|
| 127 | + if tags:
|
|
| 128 | + inputs["tags"] = " ".join(f"--tag {tag}" for tag in tags)
|
|
| 121 | 129 | |
| 122 | 130 | return inputs
|
| 123 | 131 | |
| ... | ... | @@ -157,7 +165,7 @@ def main() -> int: |
| 157 | 165 | with open(token_file) as f:
|
| 158 | 166 | trigger_token = f.read().strip()
|
| 159 | 167 | |
| 160 | - inputs = build_inputs(args.step_name, args.publish_url, args.publish_dir, args.tag)
|
|
| 168 | + inputs = build_inputs(args.step_name, args.publish_url, args.publish_dir, args.tags)
|
|
| 161 | 169 | if inputs is None:
|
| 162 | 170 | logger.info(f"No CI inputs for step {args.step_name!r}, skipping.")
|
| 163 | 171 | return 0
|