Files
TheRock/build_tools/github_actions/tests/post_build_upload_test.py
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

295 lines
11 KiB
Python

#!/usr/bin/env python
"""Unit tests for post_build_upload.py upload functions.
Tests verify that the 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
from pathlib import Path
from unittest import mock
# 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 post_build_upload 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 post_build_upload
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 TestUploadLogs(unittest.TestCase):
"""Tests for upload_logs()."""
def test_uploads_log_files(self):
"""Verify log files end up at the correct paths; raw ccache excluded."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
log_dir = build_dir / "logs"
log_dir.mkdir()
(log_dir / "build.log").write_text("build output")
(log_dir / "ninja_logs.tar.gz").write_bytes(b"gzip")
(log_dir / "ccache_logs.tar.zst").write_bytes(b"compressed")
ccache_dir = log_dir / "ccache"
ccache_dir.mkdir()
(ccache_dir / "ccache.log").write_text("verbose trace")
backend = LocalStorageBackend(staging_dir)
post_build_upload.upload_logs(
"gfx94X-dcgpu", build_dir, output_root, backend
)
base = staging_dir / "12345-linux" / "logs" / "gfx94X-dcgpu"
self.assertTrue((base / "build.log").is_file())
self.assertTrue((base / "ninja_logs.tar.gz").is_file())
self.assertTrue((base / "ccache_logs.tar.zst").is_file())
self.assertFalse((base / "ccache" / "ccache.log").exists())
def test_build_observability_uploaded(self):
"""Verify build_observability.html ends up in the log directory."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
log_dir = build_dir / "logs"
log_dir.mkdir()
(log_dir / "build_observability.html").write_text("<html></html>")
backend = LocalStorageBackend(staging_dir)
post_build_upload.upload_logs(
"gfx94X-dcgpu", build_dir, output_root, backend
)
self.assertTrue(
(
staging_dir
/ "12345-linux"
/ "logs"
/ "gfx94X-dcgpu"
/ "build_observability.html"
).is_file()
)
def test_log_index_uploaded(self):
"""Verify log index.html ends up in the log directory."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
log_dir = build_dir / "logs"
log_dir.mkdir()
(log_dir / "index.html").write_text("<html></html>")
backend = LocalStorageBackend(staging_dir)
post_build_upload.upload_logs(
"gfx94X-dcgpu", build_dir, output_root, backend
)
self.assertTrue(
(
staging_dir / "12345-linux" / "logs" / "gfx94X-dcgpu" / "index.html"
).is_file()
)
def test_resource_profiler_flattened(self):
"""Verify resource profiler files are uploaded both in subdirectory and flattened."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
log_dir = build_dir / "logs"
prof_dir = log_dir / "therock-build-prof"
prof_dir.mkdir(parents=True)
(prof_dir / "comp-summary.html").write_text("<html></html>")
(prof_dir / "comp-summary.md").write_text("# Summary")
backend = LocalStorageBackend(staging_dir)
post_build_upload.upload_logs(
"gfx94X-dcgpu", build_dir, output_root, backend
)
base = staging_dir / "12345-linux" / "logs" / "gfx94X-dcgpu"
# Subdirectory copy (from upload_directory)
self.assertTrue(
(base / "therock-build-prof" / "comp-summary.html").is_file()
)
self.assertTrue((base / "therock-build-prof" / "comp-summary.md").is_file())
# Flattened copy (explicit upload_file calls)
self.assertTrue((base / "comp-summary.html").is_file())
self.assertTrue((base / "comp-summary.md").is_file())
def test_no_log_dir_skips(self):
"""Verify no uploads happen when log dir doesn't exist."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
backend = LocalStorageBackend(staging_dir)
# Should not raise
post_build_upload.upload_logs(
"gfx94X-dcgpu", build_dir, output_root, backend
)
class TestUploadManifest(unittest.TestCase):
"""Tests for upload_manifest()."""
def test_manifest_uploaded(self):
"""Verify manifest ends up at the correct path."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
manifest_dir = build_dir / "base" / "aux-overlay" / "build"
manifest_dir.mkdir(parents=True)
(manifest_dir / "therock_manifest.json").write_text("{}")
backend = LocalStorageBackend(staging_dir)
post_build_upload.upload_manifest(
"gfx94X-dcgpu", build_dir, output_root, backend
)
self.assertTrue(
(
staging_dir
/ "12345-linux"
/ "manifests"
/ "gfx94X-dcgpu"
/ "therock_manifest.json"
).is_file()
)
def test_missing_manifest_raises(self):
"""Verify FileNotFoundError when manifest doesn't exist."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp, tempfile.TemporaryDirectory() as staging:
build_dir = Path(tmp)
staging_dir = Path(staging)
backend = LocalStorageBackend(staging_dir)
with self.assertRaises(FileNotFoundError):
post_build_upload.upload_manifest(
"gfx94X-dcgpu", build_dir, output_root, backend
)
class TestWriteGhaBuildSummary(unittest.TestCase):
"""Tests for write_gha_build_summary()."""
@mock.patch("post_build_upload.gha_append_step_summary")
def test_summary_with_observability(self, mock_summary):
"""Verify observability link included when the report exists."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp:
build_dir = Path(tmp)
log_dir = build_dir / "logs"
log_dir.mkdir()
(log_dir / "build_observability.html").write_text("<html></html>")
post_build_upload.write_gha_build_summary(
"gfx94X-dcgpu", build_dir, output_root, "success"
)
calls = [c[0][0] for c in mock_summary.call_args_list]
self.assertEqual(len(calls), 4) # logs, observability, artifacts, manifest
self.assertIn(
"https://therock-ci-artifacts.s3.amazonaws.com/12345-linux/logs/gfx94X-dcgpu/index.html",
calls[0],
)
self.assertIn(
"https://therock-ci-artifacts.s3.amazonaws.com/12345-linux/logs/gfx94X-dcgpu/build_observability.html",
calls[1],
)
self.assertIn(
"https://therock-ci-artifacts.s3.amazonaws.com/12345-linux/index.html",
calls[2],
)
self.assertIn(
"https://therock-ci-artifacts.s3.amazonaws.com/12345-linux/manifests/gfx94X-dcgpu/therock_manifest.json",
calls[3],
)
@mock.patch("post_build_upload.gha_append_step_summary")
def test_summary_without_observability(self, mock_summary):
"""Verify observability link omitted when the report was not generated."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp:
build_dir = Path(tmp)
post_build_upload.write_gha_build_summary(
"gfx94X-dcgpu", build_dir, output_root, "success"
)
calls = [c[0][0] for c in mock_summary.call_args_list]
self.assertEqual(len(calls), 3) # logs, artifacts, manifest
for call in calls:
self.assertNotIn("build_observability", call)
@mock.patch("post_build_upload.gha_append_step_summary")
def test_summary_failure_skips_artifacts(self, mock_summary):
"""Verify artifact link is skipped when job failed."""
output_root = _make_output_root()
with tempfile.TemporaryDirectory() as tmp:
build_dir = Path(tmp)
log_dir = build_dir / "logs"
log_dir.mkdir()
(log_dir / "build_observability.html").write_text("<html></html>")
post_build_upload.write_gha_build_summary(
"gfx94X-dcgpu", build_dir, output_root, "failure"
)
calls = [c[0][0] for c in mock_summary.call_args_list]
self.assertEqual(len(calls), 3) # logs, observability, manifest (no artifacts)
for call in calls:
self.assertNotIn("index-gfx94X-dcgpu.html", call)
self.assertNotIn("12345-linux/index.html", call)
@mock.patch("post_build_upload.gha_append_step_summary")
def test_summary_with_external_repo(self, mock_summary):
"""Verify external_repo prefix appears in summary URLs."""
output_root = _make_output_root(
external_repo="Fork-TheRock/",
bucket="therock-ci-artifacts-external",
)
with tempfile.TemporaryDirectory() as tmp:
build_dir = Path(tmp)
post_build_upload.write_gha_build_summary(
"gfx94X-dcgpu", build_dir, output_root, "success"
)
calls = [c[0][0] for c in mock_summary.call_args_list]
for call in calls:
self.assertIn("therock-ci-artifacts-external", call)
self.assertIn("Fork-TheRock/12345-linux", call)
if __name__ == "__main__":
unittest.main()