CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
710 lines
28 KiB
Python
710 lines
28 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright Advanced Micro Devices, Inc.
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""Unit tests for ``build_package.py`` using API-driven fixtures and real outputs.
|
|
|
|
Tests stage artifact trees by walking ``package.json`` via ``get_package_info()`` and
|
|
the same ``{Artifact}_{Component}_{suffix}`` layout consumed by
|
|
``filter_components_fromartifactory``. Config is built via ``create_package_config()``.
|
|
DEB generation runs through real ``create_versioned_deb_package()``; RPM generation
|
|
runs through real ``create_versioned_rpm_package()``; only ``package_with_dpkg_build`` /
|
|
``package_with_rpmbuild`` and ``move_packages_to_destination`` are mocked.
|
|
|
|
Run::
|
|
|
|
python3.12 build_tools/packaging/linux/tests/build_package_test.py -v
|
|
|
|
Requires Python 3.10+ (``packaging_utils`` type syntax).
|
|
"""
|
|
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
import types
|
|
import unittest
|
|
from argparse import Namespace
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
THIS_SCRIPT_DIR = Path(__file__).resolve().parent
|
|
LINUX_DIR = THIS_SCRIPT_DIR.parent
|
|
BUILD_TOOLS_DIR = LINUX_DIR.parent.parent
|
|
|
|
# Test fixture defaults (avoid unexplained literals in assertions and helpers).
|
|
TEST_ROCM_VERSION = "7.1.0"
|
|
TEST_VERSION_SUFFIX = "daily"
|
|
TEST_INSTALL_PREFIX = "/opt/rocm/core"
|
|
TEST_GFX_TARGET = "gfx1100"
|
|
TEST_GFX_TARGET_ALT = "gfx942"
|
|
TEST_PKG_TYPE_DEB = "deb"
|
|
TEST_PKG_TYPE_RPM = "rpm"
|
|
TEST_BUILD_ARCH = "x86_64"
|
|
EMPTY_GFX_ARCH = ""
|
|
|
|
PKG_FFT = "amdrocm-fft"
|
|
PKG_CORE_SDK = "amdrocm-core-sdk"
|
|
PKG_DEVELOPER_TOOLS = "amdrocm-developer-tools"
|
|
PKG_RUNTIME = "amdrocm-runtime"
|
|
PKG_DEBUGGER = "amdrocm-debugger"
|
|
PKG_CK = "amdrocm-ck"
|
|
|
|
FFT_HOST_PACKAGE = "amdrocm-fft-host7.1"
|
|
FFT_DEVICE_PACKAGE = "amdrocm-fft7.1-gfx1100"
|
|
FFT_META_PACKAGE = "amdrocm-fft7.1"
|
|
CORE_SDK_DEVICE_PACKAGE = "amdrocm-core-sdk7.1-gfx1100"
|
|
DEVELOPER_TOOLS_PACKAGE = "amdrocm-developer-tools7.1"
|
|
|
|
STAGING_PAYLOAD_NAME = "libdummy.so"
|
|
STAGING_PAYLOAD_BYTES = b"\x00"
|
|
|
|
|
|
def _setup_import_path() -> None:
|
|
"""Add packaging paths so modules resolve from any working directory."""
|
|
for path in (BUILD_TOOLS_DIR, LINUX_DIR):
|
|
path_str = str(path)
|
|
if path_str not in sys.path:
|
|
sys.path.insert(0, path_str)
|
|
|
|
|
|
def _load_module(name: str, path: Path) -> types.ModuleType:
|
|
"""Load a packaging script by path for unit tests, not CLI execution.
|
|
|
|
Uses ``importlib`` so ``build_package`` / ``deb_package`` / ``rpm_package``
|
|
resolve from ``LINUX_DIR`` regardless of cwd, without invoking each script's
|
|
``main()`` or ``if __name__ == \"__main__\"`` entry point.
|
|
"""
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
if spec is None or spec.loader is None:
|
|
raise ImportError(f"Cannot load module {name!r} from {path}")
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
_setup_import_path()
|
|
build_package = _load_module("build_package", LINUX_DIR / "build_package.py")
|
|
deb_package = _load_module("deb_package", LINUX_DIR / "deb_package.py")
|
|
rpm_package = _load_module("rpm_package", LINUX_DIR / "rpm_package.py")
|
|
|
|
# packaging_utils depends on sys.path setup above.
|
|
from packaging_utils import ( # noqa: E402
|
|
GFX_HOST,
|
|
GFX_META,
|
|
PackageConfig,
|
|
filter_components_fromartifactory,
|
|
get_package_info,
|
|
is_gfxarch_package,
|
|
is_key_defined,
|
|
update_package_name,
|
|
)
|
|
|
|
|
|
class BuildPackageTestCase(unittest.TestCase):
|
|
"""Base test case with a per-test temporary directory."""
|
|
|
|
def setUp(self) -> None:
|
|
self._temp_context = tempfile.TemporaryDirectory()
|
|
self.temp_dir = Path(self._temp_context.name)
|
|
|
|
def tearDown(self) -> None:
|
|
self._temp_context.cleanup()
|
|
|
|
def artifacts_dir(self) -> Path:
|
|
"""Return the artifact root under the temp directory."""
|
|
artifacts = self.temp_dir / "artifacts"
|
|
artifacts.mkdir(parents=True, exist_ok=True)
|
|
return artifacts
|
|
|
|
|
|
def _args(tmp: Path, **overrides: object) -> Namespace:
|
|
"""Build an ``argparse.Namespace`` mirroring ``build_package.py`` CLI flags."""
|
|
artifacts = tmp / "artifacts"
|
|
artifacts.mkdir(parents=True, exist_ok=True)
|
|
defaults: dict[str, object] = {
|
|
"artifacts_dir": artifacts,
|
|
"dest_dir": tmp / "output",
|
|
"target": [TEST_GFX_TARGET, TEST_GFX_TARGET_ALT],
|
|
"pkg_type": TEST_PKG_TYPE_DEB,
|
|
"rocm_version": TEST_ROCM_VERSION,
|
|
"version_suffix": TEST_VERSION_SUFFIX,
|
|
"install_prefix": TEST_INSTALL_PREFIX,
|
|
"runpath_pkg": False,
|
|
"enable_kpack": False,
|
|
"pkg_names": None,
|
|
"clean_build": False,
|
|
"build_variant": "",
|
|
}
|
|
defaults.update(overrides)
|
|
return Namespace(**defaults)
|
|
|
|
|
|
def _write_kpack_manifest(artifacts_dir: Path) -> None:
|
|
"""Write ``therock_manifest.json`` with ``KPACK_SPLIT_ARTIFACTS`` enabled."""
|
|
manifest_dir = artifacts_dir / "pkg"
|
|
manifest_dir.mkdir(parents=True, exist_ok=True)
|
|
manifest_path = manifest_dir / "therock_manifest.json"
|
|
manifest_path.write_text(
|
|
json.dumps({"flags": {"KPACK_SPLIT_ARTIFACTS": True}}),
|
|
encoding="utf-8",
|
|
)
|
|
if not manifest_path.exists():
|
|
raise RuntimeError(f"Failed to write kpack manifest: {manifest_path}")
|
|
|
|
|
|
def _metadata_field(metadata_text: str, field: str) -> str:
|
|
"""Return the value of a DEB control or RPM spec field (e.g. ``Package`` / ``Name``)."""
|
|
prefix = f"{field}:"
|
|
for line in metadata_text.splitlines():
|
|
if line.startswith(prefix):
|
|
return line.split(":", 1)[1].strip()
|
|
raise AssertionError(
|
|
f"Field {field!r} not found in metadata file:\n{metadata_text}"
|
|
)
|
|
|
|
|
|
def _control_field(control_text: str, field: str) -> str:
|
|
"""Return the value of a ``debian/control`` field (e.g. ``Package``)."""
|
|
return _metadata_field(control_text, field)
|
|
|
|
|
|
def _spec_field(spec_text: str, field: str) -> str:
|
|
"""Return the value of an RPM ``specfile`` field (e.g. ``Name``)."""
|
|
return _metadata_field(spec_text, field)
|
|
|
|
|
|
def _artifact_suffix_for_staging(
|
|
pkg_info: dict[str, object],
|
|
artifact: dict[str, object],
|
|
gfx_arch: str,
|
|
*,
|
|
enable_kpack: bool,
|
|
artifacts_dir: Path,
|
|
) -> str | None:
|
|
"""Compute artifact directory suffix using packaging naming rules.
|
|
|
|
Duplicates suffix routing from ``filter_components_fromartifactory`` so staged
|
|
trees use ``{Artifact}_{Component}_{suffix}`` paths production expects. If that
|
|
function's kpack/gfxarch rules change, update this helper in the same change;
|
|
otherwise tests may stage the wrong layout and still pass (false positive).
|
|
``ArtifactStagingTest`` catches gross mismatches but not every routing edge case.
|
|
"""
|
|
if enable_kpack:
|
|
if gfx_arch == GFX_META:
|
|
return None
|
|
if gfx_arch == GFX_HOST:
|
|
dir_suffix = "generic"
|
|
elif is_gfxarch_package(pkg_info, enable_kpack, artifacts_dir):
|
|
dir_suffix = gfx_arch
|
|
elif is_key_defined(pkg_info, "Gfxarch"):
|
|
# Staging device trees before gfx dirs exist: Gfxarch metadata still
|
|
# implies arch-specific suffixes once kpack splits are in play.
|
|
dir_suffix = gfx_arch
|
|
else:
|
|
dir_suffix = "generic"
|
|
else:
|
|
dir_suffix = (
|
|
gfx_arch
|
|
if is_gfxarch_package(pkg_info, enable_kpack, artifacts_dir)
|
|
else "generic"
|
|
)
|
|
|
|
if "Artifact_Gfxarch" in artifact:
|
|
is_artifact_gfx = str(artifact["Artifact_Gfxarch"]).lower() == "true"
|
|
if (
|
|
enable_kpack
|
|
and gfx_arch not in (GFX_HOST, GFX_META)
|
|
and not is_artifact_gfx
|
|
):
|
|
return None
|
|
return gfx_arch if is_artifact_gfx else "generic"
|
|
return dir_suffix
|
|
|
|
|
|
def _stage_package_artifacts(
|
|
pkg_name: str,
|
|
artifacts_dir: Path,
|
|
gfx_arch: str,
|
|
*,
|
|
enable_kpack: bool = True,
|
|
) -> list[Path]:
|
|
"""Stage artifact dirs + manifests from ``package.json`` via ``get_package_info``."""
|
|
pkg_info = get_package_info(pkg_name)
|
|
if enable_kpack and gfx_arch == GFX_META:
|
|
return []
|
|
|
|
created: list[Path] = []
|
|
artifactory = pkg_info.get("Artifactory", [])
|
|
if not isinstance(artifactory, list):
|
|
return created
|
|
|
|
for artifact in artifactory:
|
|
if not isinstance(artifact, dict):
|
|
continue
|
|
suffix = _artifact_suffix_for_staging(
|
|
pkg_info,
|
|
artifact,
|
|
gfx_arch,
|
|
enable_kpack=enable_kpack,
|
|
artifacts_dir=artifacts_dir,
|
|
)
|
|
if suffix is None:
|
|
continue
|
|
|
|
prefix = artifact["Artifact"]
|
|
subdirs = artifact.get("Artifact_Subdir", [])
|
|
if not isinstance(subdirs, list):
|
|
continue
|
|
|
|
for subdir in subdirs:
|
|
if not isinstance(subdir, dict):
|
|
continue
|
|
subdir_name = subdir["Name"]
|
|
components = subdir.get("Components", [])
|
|
if not isinstance(components, list):
|
|
continue
|
|
|
|
for component in components:
|
|
artifact_dir = artifacts_dir / f"{prefix}_{component}_{suffix}"
|
|
rel_path = f"{subdir_name}/{component}/{STAGING_PAYLOAD_NAME}"
|
|
payload = artifact_dir / rel_path
|
|
payload.parent.mkdir(parents=True, exist_ok=True)
|
|
payload.write_bytes(STAGING_PAYLOAD_BYTES)
|
|
manifest = artifact_dir / "artifact_manifest.txt"
|
|
manifest.write_text(f"{rel_path}\n", encoding="utf-8")
|
|
if not manifest.exists():
|
|
raise RuntimeError(f"Failed to write artifact manifest: {manifest}")
|
|
created.append(artifact_dir)
|
|
return created
|
|
|
|
|
|
def _kpack_config(tmp: Path, **overrides: object) -> PackageConfig:
|
|
"""Build kpack ``PackageConfig`` via ``create_package_config`` (not hand-built)."""
|
|
root = Path(tmp)
|
|
_write_kpack_manifest(root / "artifacts")
|
|
args = _args(root, enable_kpack=True, **overrides)
|
|
return build_package.create_package_config(args)
|
|
|
|
|
|
def _control_path(pkg_name: str, config: PackageConfig) -> Path:
|
|
"""Return path to generated ``debian/control`` for a versioned DEB build."""
|
|
updated = update_package_name(pkg_name, replace(config, versioned_pkg=True))
|
|
return Path(config.dest_dir) / config.pkg_type / updated / "debian" / "control"
|
|
|
|
|
|
def _read_control_file(pkg_name: str, config: PackageConfig) -> str:
|
|
"""Read generated ``debian/control`` after validating it was created."""
|
|
control_path = _control_path(pkg_name=pkg_name, config=config)
|
|
if not control_path.exists():
|
|
raise AssertionError(f"Expected control file was not created: {control_path}")
|
|
return control_path.read_text(encoding="utf-8")
|
|
|
|
|
|
def _spec_path(pkg_name: str, config: PackageConfig) -> Path:
|
|
"""Return path to generated RPM ``specfile`` for a versioned RPM build."""
|
|
updated = update_package_name(pkg_name, replace(config, versioned_pkg=True))
|
|
return Path(config.dest_dir) / config.pkg_type / updated / "specfile"
|
|
|
|
|
|
def _read_spec_file(pkg_name: str, config: PackageConfig) -> str:
|
|
"""Read generated RPM ``specfile`` after validating it was created."""
|
|
spec_path = _spec_path(pkg_name=pkg_name, config=config)
|
|
if not spec_path.exists():
|
|
raise AssertionError(f"Expected spec file was not created: {spec_path}")
|
|
return spec_path.read_text(encoding="utf-8")
|
|
|
|
|
|
def _stage_fft_kpack_tree(artifacts_dir: Path, *, include_host: bool = False) -> None:
|
|
"""Stage FFT artifacts for kpack tests; optionally include host/generic tree."""
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=artifacts_dir,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
if include_host:
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=artifacts_dir,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Artifact staging — validates production discovery APIs
|
|
# ---------------------------------------------------------------------------
|
|
class ArtifactStagingTest(BuildPackageTestCase):
|
|
"""``_stage_package_artifacts`` produces trees ``filter_components`` accepts."""
|
|
|
|
def test_staged_fft_host_artifacts_discovered(self) -> None:
|
|
artifacts = self.artifacts_dir()
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=artifacts,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
sourcedirs = filter_components_fromartifactory(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=artifacts,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
self.assertTrue(sourcedirs)
|
|
|
|
def test_staged_fft_device_artifacts_discovered(self) -> None:
|
|
artifacts = self.artifacts_dir()
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=artifacts,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
sourcedirs = filter_components_fromartifactory(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=artifacts,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
self.assertTrue(sourcedirs)
|
|
self.assertTrue(
|
|
is_gfxarch_package(
|
|
pkg_info=get_package_info(PKG_FFT),
|
|
enable_kpack=True,
|
|
artifacts_dir=artifacts,
|
|
)
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# create_versioned_deb_package — real control file generation
|
|
# ---------------------------------------------------------------------------
|
|
class CreateVersionedDebPackageTest(BuildPackageTestCase):
|
|
"""Real ``create_versioned_deb_package`` with API-staged artifacts."""
|
|
|
|
@patch.object(deb_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(deb_package, "package_with_dpkg_build")
|
|
def test_fft_host_generates_control_file(
|
|
self, _mock_dpkg: object, _mock_move: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir)
|
|
# Host naming requires gfx dirs on disk (#5874); runtime dep needs artifacts
|
|
# in pkg_list for convert_to_versiondependency.
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_RUNTIME,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
host_cfg = replace(cfg, gfx_arch=GFX_HOST)
|
|
|
|
deb_package.create_versioned_deb_package(pkg_name=PKG_FFT, config=host_cfg)
|
|
|
|
control = _read_control_file(pkg_name=PKG_FFT, config=host_cfg)
|
|
self.assertEqual(_control_field(control, "Package"), FFT_HOST_PACKAGE)
|
|
self.assertEqual(_control_field(control, "Architecture"), "amd64")
|
|
self.assertIn("amdrocm-runtime", _control_field(control, "Depends"))
|
|
|
|
@patch.object(deb_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(deb_package, "package_with_dpkg_build")
|
|
def test_fft_device_generates_control_file(
|
|
self, _mock_dpkg: object, _mock_move: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
device_cfg = replace(cfg, gfx_arch=TEST_GFX_TARGET)
|
|
|
|
deb_package.create_versioned_deb_package(pkg_name=PKG_FFT, config=device_cfg)
|
|
|
|
control = _read_control_file(pkg_name=PKG_FFT, config=device_cfg)
|
|
self.assertEqual(_control_field(control, "Package"), FFT_DEVICE_PACKAGE)
|
|
|
|
@patch.object(deb_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(deb_package, "package_with_dpkg_build")
|
|
def test_fft_meta_generates_control_file(
|
|
self, _mock_dpkg: object, _mock_move: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir)
|
|
meta_cfg = replace(cfg, gfx_arch=GFX_META)
|
|
|
|
deb_package.create_versioned_deb_package(pkg_name=PKG_FFT, config=meta_cfg)
|
|
|
|
control = _read_control_file(pkg_name=PKG_FFT, config=meta_cfg)
|
|
self.assertEqual(_control_field(control, "Package"), FFT_META_PACKAGE)
|
|
|
|
@patch.object(deb_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(deb_package, "package_with_dpkg_build")
|
|
def test_core_sdk_device_meta_generates_control_file(
|
|
self, _mock_dpkg: object, _mock_move: object
|
|
) -> None:
|
|
"""Gfx-arch metapackage ``amdrocm-core-sdk`` device variant (#6093)."""
|
|
cfg = _kpack_config(self.temp_dir)
|
|
device_cfg = replace(cfg, gfx_arch=TEST_GFX_TARGET)
|
|
|
|
deb_package.create_versioned_deb_package(
|
|
pkg_name=PKG_CORE_SDK, config=device_cfg
|
|
)
|
|
|
|
control = _read_control_file(pkg_name=PKG_CORE_SDK, config=device_cfg)
|
|
self.assertEqual(_control_field(control, "Package"), CORE_SDK_DEVICE_PACKAGE)
|
|
# debian_replace_devel_name maps -devel → -dev in DEB Depends.
|
|
self.assertIn("amdrocm-core-dev", _control_field(control, "Depends"))
|
|
|
|
@patch.object(deb_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(deb_package, "package_with_dpkg_build")
|
|
def test_developer_tools_versioned_metapackage_control(
|
|
self, _mock_dpkg: object, _mock_move: object
|
|
) -> None:
|
|
"""Simple kpack metapackage with no Artifactory entries."""
|
|
cfg = _kpack_config(self.temp_dir)
|
|
# convert_to_versiondependency only keeps amdrocm deps present in pkg_list.
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_DEBUGGER,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=EMPTY_GFX_ARCH,
|
|
enable_kpack=True,
|
|
)
|
|
versioned_cfg = replace(cfg, gfx_arch=EMPTY_GFX_ARCH)
|
|
|
|
deb_package.create_versioned_deb_package(
|
|
pkg_name=PKG_DEVELOPER_TOOLS, config=versioned_cfg
|
|
)
|
|
|
|
control = _read_control_file(pkg_name=PKG_DEVELOPER_TOOLS, config=versioned_cfg)
|
|
self.assertEqual(_control_field(control, "Package"), DEVELOPER_TOOLS_PACKAGE)
|
|
self.assertIn("amdrocm-debugger", _control_field(control, "Depends"))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# create_versioned_rpm_package — real spec file generation
|
|
# ---------------------------------------------------------------------------
|
|
class CreateVersionedRpmPackageTest(BuildPackageTestCase):
|
|
"""Real ``create_versioned_rpm_package`` with API-staged artifacts."""
|
|
|
|
@patch.object(rpm_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(rpm_package, "package_with_rpmbuild")
|
|
def test_fft_host_generates_spec_file(
|
|
self, _mock_rpmbuild: object, _mock_move: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir, pkg_type=TEST_PKG_TYPE_RPM)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_RUNTIME,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=GFX_HOST,
|
|
enable_kpack=True,
|
|
)
|
|
host_cfg = replace(cfg, gfx_arch=GFX_HOST)
|
|
|
|
rpm_package.create_versioned_rpm_package(pkg_name=PKG_FFT, config=host_cfg)
|
|
|
|
spec = _read_spec_file(pkg_name=PKG_FFT, config=host_cfg)
|
|
self.assertEqual(_spec_field(spec, "Name"), FFT_HOST_PACKAGE)
|
|
self.assertEqual(_spec_field(spec, "BuildArch"), TEST_BUILD_ARCH)
|
|
self.assertIn("amdrocm-runtime", _spec_field(spec, "Requires"))
|
|
|
|
@patch.object(rpm_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(rpm_package, "package_with_rpmbuild")
|
|
def test_fft_device_generates_spec_file(
|
|
self, _mock_rpmbuild: object, _mock_move: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir, pkg_type=TEST_PKG_TYPE_RPM)
|
|
_stage_package_artifacts(
|
|
pkg_name=PKG_FFT,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
gfx_arch=TEST_GFX_TARGET,
|
|
enable_kpack=True,
|
|
)
|
|
device_cfg = replace(cfg, gfx_arch=TEST_GFX_TARGET)
|
|
|
|
rpm_package.create_versioned_rpm_package(pkg_name=PKG_FFT, config=device_cfg)
|
|
|
|
spec = _read_spec_file(pkg_name=PKG_FFT, config=device_cfg)
|
|
self.assertEqual(_spec_field(spec, "Name"), FFT_DEVICE_PACKAGE)
|
|
|
|
@patch.object(rpm_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(rpm_package, "package_with_rpmbuild")
|
|
def test_fft_meta_generates_spec_file(
|
|
self, _mock_rpmbuild: object, _mock_move: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir, pkg_type=TEST_PKG_TYPE_RPM)
|
|
meta_cfg = replace(cfg, gfx_arch=GFX_META)
|
|
|
|
rpm_package.create_versioned_rpm_package(pkg_name=PKG_FFT, config=meta_cfg)
|
|
|
|
spec = _read_spec_file(pkg_name=PKG_FFT, config=meta_cfg)
|
|
self.assertEqual(_spec_field(spec, "Name"), FFT_META_PACKAGE)
|
|
|
|
@patch.object(rpm_package, "move_packages_to_destination", return_value=[])
|
|
@patch.object(rpm_package, "package_with_rpmbuild")
|
|
def test_core_sdk_device_meta_generates_spec_file(
|
|
self, _mock_rpmbuild: object, _mock_move: object
|
|
) -> None:
|
|
"""Gfx-arch metapackage ``amdrocm-core-sdk`` device variant (#6093)."""
|
|
cfg = _kpack_config(self.temp_dir, pkg_type=TEST_PKG_TYPE_RPM)
|
|
device_cfg = replace(cfg, gfx_arch=TEST_GFX_TARGET)
|
|
|
|
rpm_package.create_versioned_rpm_package(
|
|
pkg_name=PKG_CORE_SDK, config=device_cfg
|
|
)
|
|
|
|
spec = _read_spec_file(pkg_name=PKG_CORE_SDK, config=device_cfg)
|
|
self.assertEqual(_spec_field(spec, "Name"), CORE_SDK_DEVICE_PACKAGE)
|
|
# RPM keeps -devel naming (no debian_replace_devel_name mapping).
|
|
self.assertIn("amdrocm-core-devel", _spec_field(spec, "Requires"))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# build_package_variants — routing with real artifact detection (#5874)
|
|
# ---------------------------------------------------------------------------
|
|
class BuildPackageVariantsRoutingTest(BuildPackageTestCase):
|
|
"""Top-level routing using real ``is_gfxarch_package`` / staged artifacts."""
|
|
|
|
@patch.object(build_package, "build_gfxarch_package_variants", return_value=[])
|
|
@patch.object(build_package, "build_simple_package_variants")
|
|
def test_fft_with_staged_artifacts_routes_to_gfxarch(
|
|
self, mock_simple: object, mock_gfxarch: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir)
|
|
_stage_fft_kpack_tree(cfg.artifacts_dir)
|
|
build_package.build_package_variants(pkg_name=PKG_FFT, config=cfg)
|
|
mock_gfxarch.assert_called_once_with(PKG_FFT, cfg)
|
|
mock_simple.assert_not_called()
|
|
|
|
@patch.object(build_package, "build_gfxarch_package_variants")
|
|
@patch.object(build_package, "build_simple_package_variants", return_value=[])
|
|
def test_fft_without_gfx_artifacts_routes_to_simple(
|
|
self, mock_simple: object, mock_gfxarch: object
|
|
) -> None:
|
|
"""#5874: Gfxarch metadata alone must not trigger gfx splits without artifacts."""
|
|
cfg = _kpack_config(self.temp_dir)
|
|
pkg_info = get_package_info(PKG_FFT)
|
|
self.assertFalse(
|
|
is_gfxarch_package(
|
|
pkg_info=pkg_info,
|
|
enable_kpack=True,
|
|
artifacts_dir=cfg.artifacts_dir,
|
|
)
|
|
)
|
|
build_package.build_package_variants(pkg_name=PKG_FFT, config=cfg)
|
|
mock_simple.assert_called_once_with(PKG_FFT, cfg)
|
|
mock_gfxarch.assert_not_called()
|
|
|
|
@patch.object(build_package, "build_gfxarch_package_variants", return_value=[])
|
|
@patch.object(build_package, "build_simple_package_variants")
|
|
def test_core_sdk_metapackage_routes_to_gfxarch(
|
|
self, mock_simple: object, mock_gfxarch: object
|
|
) -> None:
|
|
"""Gfx-arch metapackage routes to gfxarch builder even without artifacts (#6093)."""
|
|
cfg = _kpack_config(self.temp_dir)
|
|
build_package.build_package_variants(pkg_name=PKG_CORE_SDK, config=cfg)
|
|
mock_gfxarch.assert_called_once_with(PKG_CORE_SDK, cfg)
|
|
mock_simple.assert_not_called()
|
|
|
|
@patch.object(build_package, "build_gfxarch_package_variants")
|
|
@patch.object(build_package, "build_simple_package_variants", return_value=[])
|
|
def test_developer_tools_routes_to_simple(
|
|
self, mock_simple: object, mock_gfxarch: object
|
|
) -> None:
|
|
cfg = _kpack_config(self.temp_dir)
|
|
build_package.build_package_variants(pkg_name=PKG_DEVELOPER_TOOLS, config=cfg)
|
|
mock_simple.assert_called_once_with(PKG_DEVELOPER_TOOLS, cfg)
|
|
mock_gfxarch.assert_not_called()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# create_package_config — CLI → PackageConfig (real function, no hand-built config)
|
|
# ---------------------------------------------------------------------------
|
|
class CreatePackageConfigTest(BuildPackageTestCase):
|
|
"""``create_package_config`` maps CLI args to ``PackageConfig``."""
|
|
|
|
def test_explicit_targets_in_kpack_mode(self) -> None:
|
|
cfg = build_package.create_package_config(
|
|
_args(
|
|
self.temp_dir,
|
|
enable_kpack=True,
|
|
target=[TEST_GFX_TARGET, TEST_GFX_TARGET_ALT],
|
|
)
|
|
)
|
|
self.assertTrue(cfg.enable_kpack)
|
|
self.assertEqual(cfg.gfxarch_list, (TEST_GFX_TARGET, TEST_GFX_TARGET_ALT))
|
|
|
|
def test_auto_detect_kpack_from_manifest(self) -> None:
|
|
_write_kpack_manifest(self.artifacts_dir())
|
|
cfg = build_package.create_package_config(_args(self.temp_dir))
|
|
self.assertTrue(cfg.enable_kpack)
|
|
|
|
def test_invalid_rocm_version_raises(self) -> None:
|
|
with self.assertRaises(ValueError):
|
|
build_package.create_package_config(
|
|
_args(self.temp_dir, rocm_version="7"),
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# load_kpack_from_manifest
|
|
# ---------------------------------------------------------------------------
|
|
class LoadKpackFromManifestTest(BuildPackageTestCase):
|
|
"""``load_kpack_from_manifest`` reads ``therock_manifest.json`` kpack flags."""
|
|
|
|
def test_true_when_kpack_flag_set(self) -> None:
|
|
_write_kpack_manifest(self.artifacts_dir())
|
|
self.assertTrue(
|
|
build_package.load_kpack_from_manifest(artifacts_dir=self.artifacts_dir())
|
|
)
|
|
|
|
def test_false_when_no_manifest(self) -> None:
|
|
self.assertFalse(
|
|
build_package.load_kpack_from_manifest(artifacts_dir=self.artifacts_dir())
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# parse_input_package_list — real package.json names
|
|
# ---------------------------------------------------------------------------
|
|
class ParseInputPackageListTest(BuildPackageTestCase):
|
|
"""``parse_input_package_list`` filters names against ``package.json``."""
|
|
|
|
def test_explicit_pkg_names_filter_package_json(self) -> None:
|
|
pkg_list, skipped = build_package.parse_input_package_list(
|
|
pkg_name=[PKG_CORE_SDK, PKG_CK, "no-such-package"],
|
|
artifact_dir=self.artifacts_dir(),
|
|
)
|
|
self.assertEqual(set(pkg_list), {PKG_CORE_SDK, PKG_CK})
|
|
self.assertEqual(skipped, [])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|