Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-05 08:17:12

0001 #!/usr/bin/env python3
0002 """Self-tests for select_lockfile.py.
0003 
0004 Guards asset-name parsing and the selection rules. Picking the wrong lockfile
0005 does not fail here: it fails minutes later in a configure step, on a runner.
0006 
0007 Run directly; non-zero exit on failure. Also collectable by pytest.
0008 """
0009 
0010 from __future__ import annotations
0011 
0012 import sys
0013 from pathlib import Path
0014 from typing import Dict, Optional
0015 
0016 HERE = Path(__file__).resolve().parent
0017 sys.path.insert(0, str(HERE))
0018 
0019 import select_lockfile as sl  # noqa: E402
0020 
0021 # Real asset names from v24.0.0, the first release carrying flavors, in the
0022 # shape the GitHub releases API returns them.
0023 V24_ASSETS = [
0024     "spack_darwin-tahoe-aarch64.lock",
0025     "spack_darwin-tahoe-aarch64_apple-clang@17.0.0_cxx23.lock",
0026     "spack_linux-almalinux9-x86_64.lock",
0027     "spack_linux-almalinux9-x86_64_gcc@15.2.1_cxx23.lock",
0028     "spack_linux-ubuntu26.04-aarch64_gcc@15.2.0_cxx23.lock",
0029     "spack_linux-ubuntu26.04-x86_64.lock",
0030     "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx20.lock",
0031     "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx23.lock",
0032     "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx23_cuda13.lock",
0033     "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx23_rocm-gfx90a.lock",
0034     "spack_linux-ubuntu26.04-x86_64_llvm@22.1.8_cxx23.lock",
0035 ]
0036 
0037 # v23.3.1, pre-flavor, so today's host selections stay covered too.
0038 V23_ASSETS = [
0039     "spack_linux-ubuntu24.04-x86_64.lock",
0040     "spack_linux-ubuntu24.04-x86_64_gcc@13.3.0_cxx20.lock",
0041     "spack_linux-ubuntu24.04-x86_64_llvm@22.1.7_cxx20.lock",
0042     "spack_linux-ubuntu24.04-x86_64_llvm@22.1.7_cxx23.lock",
0043 ]
0044 
0045 UBUNTU26 = "linux-ubuntu26.04-x86_64"
0046 UBUNTU24 = "linux-ubuntu24.04-x86_64"
0047 
0048 
0049 def _release(names: list[str]) -> Dict:
0050     return {
0051         "assets": [
0052             {"name": n, "browser_download_url": f"https://example.invalid/{n}"}
0053             for n in names
0054         ]
0055     }
0056 
0057 
0058 def _select(
0059     names: list[str],
0060     arch: str,
0061     compiler: Optional[str],
0062     cxx: str = "cxx20",
0063     flavor: Optional[str] = None,
0064 ) -> str:
0065     """Select against a synthetic release, returning the chosen asset name."""
0066     lockfiles = sl.parse_assets(_release(names))
0067     url = sl.select_lockfile(lockfiles, arch, compiler, cxx, flavor)
0068     return url.rsplit("/", 1)[-1]
0069 
0070 
0071 # --- flavor token extraction -----------------------------------------------
0072 
0073 
0074 def test_extract_flavor_host_specs():
0075     assert sl.extract_flavor("gcc@15.2.0_cxx23") is None
0076     assert sl.extract_flavor("gcc@13.3.0") is None, "pre-cxx spec has no flavor"
0077     assert sl.extract_flavor("default") is None
0078 
0079 
0080 def test_extract_flavor_accelerator_specs():
0081     assert sl.extract_flavor("gcc@15.2.0_cxx23_cuda13") == "cuda13"
0082     assert sl.extract_flavor("gcc@15.2.0_cxx23_rocm-gfx90a") == "rocm-gfx90a"
0083 
0084 
0085 def test_extract_flavor_keeps_underscores_in_flavor_name():
0086     # Not shipped today, but the grammar permits it and take-last would truncate.
0087     assert sl.extract_flavor("gcc@15.2.0_cxx23_cuda13_sm90") == "cuda13_sm90"
0088 
0089 
0090 def test_normalize_flavor():
0091     assert sl.normalize_flavor("host") is None, "'host' is the plain CPU stack"
0092     assert sl.normalize_flavor("") is None
0093     assert sl.normalize_flavor(None) is None
0094     assert sl.normalize_flavor("  cuda13 ") == "cuda13"
0095 
0096 
0097 # --- flavor selection -------------------------------------------------------
0098 
0099 
0100 def test_flavored_lockfile_is_selected():
0101     got = _select(V24_ASSETS, UBUNTU26, "gcc@15.2.0", cxx="cxx23", flavor="cuda13")
0102     assert got == "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx23_cuda13.lock", got
0103 
0104 
0105 def test_flavor_name_with_dash_is_selected():
0106     got = _select(V24_ASSETS, UBUNTU26, "gcc@15.2.0", cxx="cxx23", flavor="rocm-gfx90a")
0107     assert (
0108         got == "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx23_rocm-gfx90a.lock"
0109     ), got
0110 
0111 
0112 def test_host_request_never_picks_a_flavored_lockfile():
0113     # Before flavors were parsed, these were ordinary candidates in the pool.
0114     for cxx in ("cxx20", "cxx23"):
0115         got = _select(V24_ASSETS, UBUNTU26, "gcc@15.2.0", cxx=cxx)
0116         assert sl.extract_flavor(got) is None, f"{cxx} picked flavored {got}"
0117 
0118 
0119 def test_flavor_falls_back_across_cxx_but_not_across_flavor():
0120     # Flavors ship at cxx23 only, so cxx20+cuda13 must land on the cxx23 CUDA
0121     # stack -- never the cxx20 *host* stack, the wrong-but-plausible answer.
0122     got = _select(V24_ASSETS, UBUNTU26, "gcc@15.2.0", cxx="cxx20", flavor="cuda13")
0123     assert got == "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx23_cuda13.lock", got
0124 
0125 
0126 def test_unknown_flavor_exits_rather_than_falling_back():
0127     # Returning the host stack would surface as a missing-CUDA configure error
0128     # much later, pointing nowhere near the cause.
0129     try:
0130         _select(V24_ASSETS, UBUNTU26, "gcc@15.2.0", cxx="cxx23", flavor="cuda12")
0131     except SystemExit as e:
0132         assert e.code == 1, e.code
0133     else:
0134         raise AssertionError("expected a hard failure for an unavailable flavor")
0135 
0136 
0137 def test_flavor_request_on_arch_without_flavors_exits():
0138     try:
0139         _select(V23_ASSETS, UBUNTU24, "gcc@13.3.0", cxx="cxx20", flavor="cuda13")
0140     except SystemExit as e:
0141         assert e.code == 1, e.code
0142     else:
0143         raise AssertionError("expected a hard failure on a flavorless release")
0144 
0145 
0146 # --- pre-existing selection rules, unchanged by the flavor axis --------------
0147 
0148 
0149 def test_exact_compiler_and_cxx_match():
0150     got = _select(V24_ASSETS, UBUNTU26, "gcc@15.2.0", cxx="cxx20")
0151     assert got == "spack_linux-ubuntu26.04-x86_64_gcc@15.2.0_cxx20.lock", got
0152 
0153 
0154 def test_clang_is_an_alias_for_llvm():
0155     got = _select(V24_ASSETS, UBUNTU26, "clang@22.1.8", cxx="cxx23")
0156     assert got == "spack_linux-ubuntu26.04-x86_64_llvm@22.1.8_cxx23.lock", got
0157 
0158 
0159 def test_unknown_compiler_version_uses_highest_of_family():
0160     got = _select(V23_ASSETS, UBUNTU24, "llvm@22.1.1", cxx="cxx23")
0161     assert got == "spack_linux-ubuntu24.04-x86_64_llvm@22.1.7_cxx23.lock", got
0162 
0163 
0164 def test_no_compiler_uses_the_arch_default():
0165     got = _select(V24_ASSETS, UBUNTU26, None, cxx="cxx20")
0166     assert got == "spack_linux-ubuntu26.04-x86_64.lock", got
0167 
0168 
0169 def test_v23_host_selection_is_unchanged():
0170     # In production today: whatever else moves, this must not.
0171     got = _select(V23_ASSETS, UBUNTU24, "gcc@13.3.0", cxx="cxx20")
0172     assert got == "spack_linux-ubuntu24.04-x86_64_gcc@13.3.0_cxx20.lock", got
0173 
0174 
0175 def _main() -> int:
0176     failures = 0
0177     for name, fn in sorted(globals().items()):
0178         if name.startswith("test_") and callable(fn):
0179             try:
0180                 fn()
0181                 print(f"ok   {name}")
0182             except AssertionError as e:
0183                 failures += 1
0184                 print(f"FAIL {name}: {e}")
0185     print(f"\n{failures} failure(s)")
0186     return 1 if failures else 0
0187 
0188 
0189 if __name__ == "__main__":
0190     sys.exit(_main())