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
242 lines
9.8 KiB
Python
242 lines
9.8 KiB
Python
#!/usr/bin/env python
|
|
"""Unit tests for upload_python_packages.py.
|
|
|
|
Tests verify that upload functions pass correct StorageLocations to the
|
|
StorageBackend, producing the expected file layout. Uses LocalStorageBackend
|
|
with a temp directory so no mocking of subprocess or boto3 is needed.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
import unittest.mock
|
|
from pathlib import Path
|
|
|
|
# Add build_tools to path so _therock_utils is importable.
|
|
sys.path.insert(0, os.fspath(Path(__file__).parent.parent.parent))
|
|
# Add github_actions to path so upload_python_packages is importable.
|
|
sys.path.insert(0, os.fspath(Path(__file__).parent.parent))
|
|
|
|
from _therock_utils.workflow_outputs import WorkflowOutputRoot
|
|
from _therock_utils.storage_backend import LocalStorageBackend
|
|
import upload_python_packages
|
|
|
|
|
|
def _make_output_root(
|
|
run_id="12345",
|
|
platform="linux",
|
|
bucket="therock-ci-artifacts",
|
|
external_repo="",
|
|
):
|
|
return WorkflowOutputRoot(
|
|
bucket=bucket,
|
|
external_repo=external_repo,
|
|
run_id=run_id,
|
|
platform=platform,
|
|
)
|
|
|
|
|
|
class TestFindPackageFiles(unittest.TestCase):
|
|
"""Tests for find_package_files()."""
|
|
|
|
def test_finds_wheels_sdists_and_index(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
dist_dir = Path(tmp)
|
|
(dist_dir / "rocm-1.0.whl").write_bytes(b"whl")
|
|
(dist_dir / "rocm-1.0.tar.gz").write_bytes(b"sdist")
|
|
(dist_dir / "index.html").write_text("<html></html>")
|
|
(dist_dir / "unrelated.txt").write_text("ignore")
|
|
|
|
files = upload_python_packages.find_package_files(dist_dir)
|
|
names = sorted(f.name for f in files)
|
|
self.assertEqual(names, ["index.html", "rocm-1.0.tar.gz", "rocm-1.0.whl"])
|
|
|
|
def test_empty_directory(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
files = upload_python_packages.find_package_files(Path(tmp))
|
|
self.assertEqual(files, [])
|
|
|
|
|
|
class TestUploadPackages(unittest.TestCase):
|
|
"""Tests for upload_packages()."""
|
|
|
|
def test_uploads_package_files(self):
|
|
output_root = _make_output_root()
|
|
packages_loc = output_root.python_packages("gfx94X-dcgpu")
|
|
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
|
|
dist_dir = Path(tmp)
|
|
staging_dir = Path(staging)
|
|
(dist_dir / "rocm-1.0.whl").write_bytes(b"whl")
|
|
(dist_dir / "rocm-1.0.tar.gz").write_bytes(b"sdist")
|
|
(dist_dir / "index.html").write_text("<html></html>")
|
|
|
|
backend = LocalStorageBackend(staging_dir)
|
|
upload_python_packages.upload_packages(dist_dir, packages_loc, backend)
|
|
|
|
base = staging_dir / "12345-linux" / "python" / "gfx94X-dcgpu"
|
|
self.assertTrue((base / "rocm-1.0.whl").is_file())
|
|
self.assertTrue((base / "rocm-1.0.tar.gz").is_file())
|
|
self.assertTrue((base / "index.html").is_file())
|
|
|
|
def test_no_files_raises(self):
|
|
output_root = _make_output_root()
|
|
packages_loc = output_root.python_packages("gfx94X-dcgpu")
|
|
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
|
|
dist_dir = Path(tmp)
|
|
staging_dir = Path(staging)
|
|
backend = LocalStorageBackend(staging_dir)
|
|
with self.assertRaises(FileNotFoundError):
|
|
upload_python_packages.upload_packages(dist_dir, packages_loc, backend)
|
|
|
|
def test_external_repo_prefix(self):
|
|
output_root = _make_output_root(
|
|
external_repo="Fork-TheRock/",
|
|
bucket="therock-ci-artifacts-external",
|
|
)
|
|
packages_loc = output_root.python_packages("gfx94X-dcgpu")
|
|
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
|
|
dist_dir = Path(tmp)
|
|
staging_dir = Path(staging)
|
|
(dist_dir / "rocm-1.0.whl").write_bytes(b"whl")
|
|
|
|
backend = LocalStorageBackend(staging_dir)
|
|
upload_python_packages.upload_packages(dist_dir, packages_loc, backend)
|
|
|
|
self.assertTrue(
|
|
(
|
|
staging_dir
|
|
/ "Fork-TheRock"
|
|
/ "12345-linux"
|
|
/ "python"
|
|
/ "gfx94X-dcgpu"
|
|
/ "rocm-1.0.whl"
|
|
).is_file()
|
|
)
|
|
|
|
|
|
class TestMultiArchUploadPath(unittest.TestCase):
|
|
"""Tests that multi-arch uploads go to python/ without an artifact_group subdir."""
|
|
|
|
def test_multiarch_upload_path(self):
|
|
output_root = _make_output_root()
|
|
packages_loc = output_root.python_packages("")
|
|
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
|
|
dist_dir = Path(tmp)
|
|
staging_dir = Path(staging)
|
|
(dist_dir / "rocm-1.0.whl").write_bytes(b"whl")
|
|
(dist_dir / "index.html").write_text("<html></html>")
|
|
|
|
backend = LocalStorageBackend(staging_dir)
|
|
upload_python_packages.upload_packages(dist_dir, packages_loc, backend)
|
|
|
|
base = staging_dir / "12345-linux" / "python"
|
|
self.assertTrue((base / "rocm-1.0.whl").is_file())
|
|
self.assertTrue((base / "index.html").is_file())
|
|
# Confirm no artifact_group subdirectory was created
|
|
self.assertFalse((base / "multi-arch-release").exists())
|
|
|
|
|
|
class TestGenerateIndex(unittest.TestCase):
|
|
"""Tests for generate_index() flat vs per-family auto-detection."""
|
|
|
|
def test_flat_layout_skips_client_side_index(self):
|
|
"""Flat dist/ (no subdirs) skips client index generation — the
|
|
therock-ci-artifacts bucket serves index.html from its own side,
|
|
and a client-generated index would race with the server view
|
|
when multiple jobs append to the same prefix."""
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
dist_dir = Path(tmp)
|
|
(dist_dir / "rocm_sdk_core-1.0.whl").write_bytes(b"core")
|
|
(dist_dir / "rocm_sdk_device_gfx942-1.0.whl").write_bytes(b"device")
|
|
|
|
upload_python_packages.generate_index(dist_dir, multiarch=True)
|
|
|
|
self.assertFalse((dist_dir / "index.html").exists())
|
|
self.assertFalse(any(d.is_dir() for d in dist_dir.iterdir()))
|
|
|
|
def test_per_family_layout_creates_family_indexes(self):
|
|
"""Per-family dist/ (with subdirs) creates per-family indexes, not top-level."""
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
dist_dir = Path(tmp)
|
|
(dist_dir / "rocm_sdk_core-1.0.whl").write_bytes(b"core")
|
|
(dist_dir / "gfx94X-dcgpu").mkdir()
|
|
(
|
|
dist_dir / "gfx94X-dcgpu" / "rocm_sdk_libraries_gfx94x_dcgpu-1.0.whl"
|
|
).write_bytes(b"libs")
|
|
|
|
upload_python_packages.generate_index(dist_dir, multiarch=True)
|
|
|
|
self.assertTrue((dist_dir / "gfx94X-dcgpu" / "index.html").is_file())
|
|
self.assertFalse((dist_dir / "index.html").is_file())
|
|
|
|
def test_dot_dir_treated_as_flat(self):
|
|
"""A dot-directory (e.g. .kpack_staging) is a staging artifact, not a
|
|
GPU family, so it must not flip detection into per-family mode."""
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
dist_dir = Path(tmp)
|
|
(dist_dir / "rocm_sdk_core-1.0.whl").write_bytes(b"core")
|
|
(dist_dir / ".kpack_staging").mkdir()
|
|
(dist_dir / ".kpack_staging" / "scratch.whl").write_bytes(b"scratch")
|
|
|
|
self.assertEqual(upload_python_packages.detect_family_subdirs(dist_dir), [])
|
|
|
|
upload_python_packages.generate_index(dist_dir, multiarch=True)
|
|
|
|
# Flat (kpack-split) handling: no per-family index generated.
|
|
self.assertFalse((dist_dir / ".kpack_staging" / "index.html").exists())
|
|
|
|
def test_dry_run_creates_nothing(self):
|
|
"""dry_run=True creates no files regardless of layout."""
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
dist_dir = Path(tmp)
|
|
(dist_dir / "rocm_sdk_core-1.0.whl").write_bytes(b"core")
|
|
|
|
upload_python_packages.generate_index(
|
|
dist_dir, multiarch=True, dry_run=True
|
|
)
|
|
|
|
self.assertFalse((dist_dir / "index.html").is_file())
|
|
|
|
|
|
class TestWriteGhaUploadSummary(unittest.TestCase):
|
|
"""Tests for write_gha_upload_summary() three-way families branch."""
|
|
|
|
def _make_loc(self):
|
|
return _make_output_root().python_packages("")
|
|
|
|
@unittest.mock.patch("upload_python_packages.gha_append_step_summary")
|
|
def test_none_families_single_arch(self, mock_summary):
|
|
"""families=None → single-arch summary with /index.html URL."""
|
|
upload_python_packages.write_gha_upload_summary(self._make_loc(), families=None)
|
|
|
|
text = mock_summary.call_args[0][0]
|
|
self.assertIn("/index.html", text)
|
|
self.assertNotIn("kpack-split", text)
|
|
self.assertNotIn("per-family", text.lower())
|
|
|
|
@unittest.mock.patch("upload_python_packages.gha_append_step_summary")
|
|
def test_empty_families_kpack_split(self, mock_summary):
|
|
"""families=[] → kpack-split summary with /index.html URL."""
|
|
upload_python_packages.write_gha_upload_summary(self._make_loc(), families=[])
|
|
|
|
text = mock_summary.call_args[0][0]
|
|
self.assertIn("kpack-split", text)
|
|
self.assertIn("/index.html", text)
|
|
|
|
@unittest.mock.patch("upload_python_packages.gha_append_step_summary")
|
|
def test_nonempty_families_per_family(self, mock_summary):
|
|
"""families=[...] → per-family summary with per-family index URLs."""
|
|
upload_python_packages.write_gha_upload_summary(
|
|
self._make_loc(), families=["gfx94X-dcgpu", "gfx120X-all"]
|
|
)
|
|
|
|
text = mock_summary.call_args[0][0]
|
|
self.assertIn("gfx94X-dcgpu/index.html", text)
|
|
self.assertIn("gfx120X-all/index.html", text)
|
|
self.assertNotIn("kpack-split", text)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|