Commits:
-
ce7fa79b
by Beatriz Rizental at 2026-09-16T14:32:16-03:00
Bug 40107: Execute xpcshell tests on CI
-
03eca1fb
by Beatriz Rizental at 2026-09-16T16:09:52-03:00
Bug 40107: Pass base-browser as a test tag for all browsers
8 changed files:
Changes:
.gitlab-ci.yml
| ... |
... |
@@ -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' |
.gitlab/_base.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 ]]"
|
.gitlab/_inputs.yml
| ... |
... |
@@ -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
|
.gitlab/scripts/before_script.py
|
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__":
|
.gitlab/test_marionette.yml
|
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 |
.gitlab/test_xpcshell.yml
|
|
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 |
config/tb-build-06.torproject.org
| ... |
... |
@@ -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",
|
tools/trigger-test-pipeline.py
| ... |
... |
@@ -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
|
|