Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

122
tools/test-services.py Normal file
View file

@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""Run service contracts in the pinned engine, then restart and check persistence."""
import argparse
import functools
import json
import os
import subprocess
import threading
import time
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from marionette_client import Client
ROOT = Path(__file__).resolve().parents[1]
(ROOT / "logs").mkdir(exist_ok=True)
(ROOT / "profiles").mkdir(exist_ok=True)
parser = argparse.ArgumentParser()
parser.add_argument("--candidate", action="store_true")
args = parser.parse_args()
lock = json.loads(
(ROOT / ("candidate-engine.json" if args.candidate else "engine-lock.json")).read_text()
)
profile = ROOT / "profiles" / ("contracts-" + lock["version"])
profile.mkdir(exist_ok=True)
(profile / "user.js").write_text(
"""user_pref("marionette.port",2856);
user_pref("browser.shell.checkDefaultBrowser",false);
user_pref("browser.aboutwelcome.enabled",false);
user_pref("datareporting.policy.dataSubmissionEnabled",false);
user_pref("toolkit.telemetry.reportingpolicy.firstRun",false);
"""
)
class Handler(SimpleHTTPRequestHandler):
def log_message(self, *args):
pass
def do_GET(self):
# Only test modules are served, never profiles, downloads or engine files.
target = Path(self.translate_path(self.path)).resolve()
if not any(
target.is_relative_to(ROOT / name) for name in ["tests", "services", "adapters"]
):
self.send_error(404)
return
return super().do_GET()
server = ThreadingHTTPServer(("127.0.0.1", 0), functools.partial(Handler, directory=str(ROOT)))
threading.Thread(target=server.serve_forever, daemon=True).start()
url = "http://127.0.0.1:%d/tests/contracts.html" % server.server_port
results = {}
try:
for phase in ["first", "restart"]:
env = os.environ.copy()
for key in list(env):
if key.startswith("MOZ_DISABLE_") or key == "B2G_HOMESCREEN":
env.pop(key)
with (ROOT / "logs" / ("contracts-" + phase + ".log")).open("w") as log:
proc = subprocess.Popen(
[
str(ROOT / lock["runtime"] / "firefox"),
"-no-remote",
"-headless",
"-marionette",
"--remote-allow-system-access",
"-profile",
str(profile),
"about:blank",
],
env=env,
stdout=log,
stderr=subprocess.STDOUT,
start_new_session=True,
)
try:
with Client() as client:
actual = client.execute("return Services.appinfo.platformVersion;")
assert actual == lock["version"], actual
client.call("Marionette:SetContext", {"value": "content"})
client.call(
"WebDriver:Navigate",
{"url": url + ("?restart=1" if phase == "restart" else "")},
)
for _ in range(300):
raw = client.execute(
'return document.getElementById("result")?.textContent || "";'
)
result = json.loads(raw) if raw.startswith("{") else None
if result:
break
time.sleep(0.1)
else:
page = client.execute(
"return {url:location.href,ready:document.readyState,text:document.body?.innerText};"
)
client.call("Marionette:SetContext", {"value": "chrome"})
errors = client.execute(
"return Services.console.getMessageArray().map(e=>e.message).slice(-20);"
)
raise AssertionError(
"Service tests did not complete: " + repr({"page": page, "errors": errors})
)
results[phase] = result
assert all(v is True for v in result.values()), result
client.call("Marionette:Quit", {"flags": ["eAttemptQuit"]})
finally:
try:
proc.wait(timeout=15)
except subprocess.TimeoutExpired:
proc.terminate()
proc.wait(timeout=10)
results["engine"] = lock["version"]
(ROOT / "logs/services-results.json").write_text(json.dumps(results, indent=2) + "\n")
(ROOT / "logs" / ("services-results-" + lock["version"] + ".json")).write_text(
json.dumps(results, indent=2) + "\n"
)
print(json.dumps(results, indent=2))
finally:
server.shutdown()
server.server_close()