"""Regression coverage for raising the supported browser floor. Raising ``CONSTRAINTS.MIN_VERSION`` is how the library forces an existing install to upgrade when it can no longer talk to the old browser. That path had been dead since the floor was dropped to ``alpha.1``, and it hid a bug: ``camoufox_path`` probed ``INSTALL_DIR/version.json``, which only the pre-multiversion flat layout ever wrote, so a below-floor versioned install raised ``FileNotFoundError`` instead of falling through to a fetch. """ import json import pytest from camoufox import multiversion, pkgman from camoufox.exceptions import UnsupportedVersion def _install(tmp_path, monkeypatch, layout, build, floor): """Build an install dir in the given layout and point the library at it.""" root = tmp_path / "cache" root.mkdir() (root / ".0.5_FLAG").write_text("") (root / "repo_cache.json").write_text("{}") if layout == "versioned": relative = f"browsers/official/152.0.4-{build}" (root / "config.json").write_text(json.dumps({"active_version": relative})) version_dir = root / relative version_dir.mkdir(parents=True) else: (root / "config.json").write_text("{}") version_dir = root (version_dir / "version.json").write_text( json.dumps({"version": "152.0.4", "build": build}) ) for module in (pkgman, multiversion): monkeypatch.setattr(module, "INSTALL_DIR", root) monkeypatch.setattr(multiversion, "BROWSERS_DIR", root / "browsers") monkeypatch.setattr(multiversion, "CONFIG_FILE", root / "config.json") monkeypatch.setattr(multiversion, "COMPAT_FLAG", root / ".0.5_FLAG") monkeypatch.setattr(pkgman, "VERSION_MIN", pkgman.Version(build=floor)) return root @pytest.mark.parametrize("layout", ["versioned", "legacy"]) def test_below_floor_install_is_reported_as_outdated(tmp_path, monkeypatch, layout): """A build under the floor must report as outdated, never as missing.""" _install(tmp_path, monkeypatch, layout, build="beta.29", floor="beta.30") with pytest.raises(UnsupportedVersion): pkgman.camoufox_path(download_if_missing=False) @pytest.mark.parametrize("layout", ["versioned", "legacy"]) def test_at_floor_install_is_kept(tmp_path, monkeypatch, layout): """A build at the floor is still served, in either layout.""" root = _install(tmp_path, monkeypatch, layout, build="beta.30", floor="beta.30") resolved = pkgman.camoufox_path(download_if_missing=False) expected = root if layout == "legacy" else root / "browsers/official/152.0.4-beta.30" assert resolved == expected def test_below_floor_install_triggers_a_fetch(tmp_path, monkeypatch): """The default path upgrades the install instead of raising.""" root = _install(tmp_path, monkeypatch, "versioned", build="beta.29", floor="beta.30") installed = [] class StubFetcher: def install(self): installed.append(True) relative = "browsers/official/152.0.4-beta.30" version_dir = root / relative version_dir.mkdir(parents=True) (version_dir / "version.json").write_text( json.dumps({"version": "152.0.4", "build": "beta.30"}) ) (root / "config.json").write_text(json.dumps({"active_version": relative})) monkeypatch.setattr(pkgman, "CamoufoxFetcher", StubFetcher) resolved = pkgman.camoufox_path() assert installed == [True] assert resolved == root / "browsers/official/152.0.4-beta.30" def test_root_probe_tolerates_the_versioned_layout(tmp_path, monkeypatch): """The root probe reports False, rather than raising, with no root file.""" root = tmp_path / "cache" root.mkdir() monkeypatch.setattr(pkgman, "INSTALL_DIR", root) assert pkgman._root_install_supported() is False