Train-hop langpack smoke test

browser/components/newtab/test/python/test_trainhop_langpacks.py guards against the class of regression fixed in bug 2049845: an AboutNewTabResourceMapping observer cascade that explodes memory when a train-hop newtab XPI is registered while many langpacks are active, as on MSIX, Snap and Flatpak installs, which bundle a langpack for every shipped locale.

Why it reproduces

registerFluentSources() registers a shadow Fluent source inside every active langpack’s metasource. Each shadow source only covers the locales in the XPI’s supported-locales.json that are also available, and the AboutNewTabResourceMapping.observe() comment describes how those registrations re-entered the observer without the fix.

So the test needs real locale codes on both sides: the XPI must support them and langpacks must provide them. With made-up locale codes the shadow sources are empty and the cascade never starts.

How it works

The test runs with ./mach python-test --subsuite newtab-trainhop against a local build, or GECKO_BINARY_PATH in CI. It:

  1. Starts Firefox headless under Marionette, with intl.multilingual.enabled and intl.locale.requested set to en-US.

  2. Generates a minimal langpack for every locale in browser/locales/shipped-locales, and installs them all as temporary add-ons.

  3. Builds a minimal train-hop XPI whose supported-locales.json lists en-US plus every shipped locale, which is how browser/extensions/newtab/webext-glue/moz.build packages a shipped train-hop XPI.

  4. Calls AboutNewTabResourceMapping.registerFluentSources() against that XPI from chrome JS while sampling RSS of the Firefox process tree.

The locale list comes from the tree, not from a build’s l10n repacks, so the test reproduces at the same scale on try, autoland and mozilla-central.

Interpreting pass/fail

The test fails if RSS grows by more than MAX_GROWTH_MIB (300) during the call, in which case it kills Firefox, or if fewer langpacks than expected were active. Measured locally on macOS:

RSS growth

Result

Fix backed out

> 300 MiB within a few seconds

FAIL

Fix applied

0-12 MiB

PASS

Running locally

./mach python-test --subsuite newtab-trainhop

In CI it runs as source-test-python-newtab-trainhop (py3(ntm)), defined in taskcluster/kinds/source-test/python.yml.