Files
TheRock/build_tools/tests/s3_buckets_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

307 lines
12 KiB
Python

#!/usr/bin/env python
"""Unit tests for s3_buckets.py."""
import json
import os
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
sys.path.insert(0, os.fspath(Path(__file__).parent.parent))
from _therock_utils.s3_buckets import (
get_artifacts_bucket_config,
get_artifacts_bucket_config_for_workflow_run,
get_release_bucket_config,
)
# ---------------------------------------------------------------------------
# get_artifacts_bucket_config
# ---------------------------------------------------------------------------
class TestGetArtifactsBucketConfig(unittest.TestCase):
def test_ci_rocm_therock(self):
config = get_artifacts_bucket_config(
release_type="ci", repository="ROCm/TheRock", is_pr_from_fork=False
)
self.assertEqual(config.name, "therock-ci-artifacts")
self.assertEqual(
config.write_access_iam_role,
"arn:aws:iam::692859939525:role/therock-ci",
)
def test_ci_fork_pr(self):
config = get_artifacts_bucket_config(
release_type="ci", repository="ROCm/TheRock", is_pr_from_fork=True
)
self.assertEqual(config.name, "therock-ci-artifacts-external")
# The raw lookup returns the external role for forks; the OIDC skip for
# forks happens in get_artifacts_bucket_config_for_workflow_run, not here.
self.assertEqual(config.iam_role, "therock-ci-external")
def test_ci_external_repo(self):
config = get_artifacts_bucket_config(
release_type="ci", repository="ROCm/rocm-libraries", is_pr_from_fork=False
)
self.assertEqual(config.name, "therock-ci-artifacts-external")
self.assertEqual(config.iam_role, "therock-ci-external")
def test_release_type_dev(self):
config = get_artifacts_bucket_config(
release_type="dev", repository="ROCm/TheRock", is_pr_from_fork=False
)
self.assertEqual(config.name, "therock-dev-artifacts")
self.assertEqual(config.iam_role, "therock-dev")
def test_release_type_from_rockrel(self):
config = get_artifacts_bucket_config(
release_type="nightly", repository="ROCm/rockrel", is_pr_from_fork=False
)
self.assertEqual(config.name, "therock-nightly-artifacts")
def test_release_type_invalid_raises(self):
with self.assertRaises(ValueError) as cm:
get_artifacts_bucket_config(
release_type="bogus",
repository="ROCm/TheRock",
is_pr_from_fork=False,
)
self.assertIn("bogus", str(cm.exception))
def test_empty_release_type_raises(self):
with self.assertRaises(ValueError):
get_artifacts_bucket_config(
release_type="",
repository="ROCm/TheRock",
is_pr_from_fork=False,
)
# ---------------------------------------------------------------------------
# get_release_bucket_config
# ---------------------------------------------------------------------------
class TestGetReleaseBucketConfig(unittest.TestCase):
def test_dev_tarball(self):
config = get_release_bucket_config(release_type="dev", bucket_type="tarball")
self.assertEqual(config.name, "therock-dev-tarball")
self.assertEqual(config.iam_role, "therock-dev")
self.assertEqual(
config.write_access_iam_role,
"arn:aws:iam::692859939525:role/therock-dev",
)
def test_nightly_python(self):
config = get_release_bucket_config(release_type="nightly", bucket_type="python")
self.assertEqual(config.name, "therock-nightly-python")
self.assertEqual(config.iam_role, "therock-nightly")
def test_prerelease_packages(self):
config = get_release_bucket_config(
release_type="prerelease", bucket_type="packages"
)
self.assertEqual(config.name, "therock-prerelease-packages")
self.assertEqual(config.iam_role, "therock-prerelease")
def test_all_combinations_exist(self):
for release_type in ("dev", "nightly", "prerelease"):
for bucket_type in ("tarball", "python", "packages"):
config = get_release_bucket_config(release_type, bucket_type)
self.assertEqual(config.name, f"therock-{release_type}-{bucket_type}")
def test_invalid_release_type_raises(self):
with self.assertRaises(ValueError) as cm:
get_release_bucket_config(release_type="bogus", bucket_type="tarball")
self.assertIn("bogus", str(cm.exception))
def test_empty_release_type_raises(self):
with self.assertRaises(ValueError):
get_release_bucket_config(release_type="", bucket_type="tarball")
def test_ci_release_type_raises(self):
with self.assertRaises(ValueError):
get_release_bucket_config(release_type="ci", bucket_type="tarball")
def test_invalid_bucket_type_raises(self):
with self.assertRaises(ValueError) as cm:
get_release_bucket_config(release_type="dev", bucket_type="wheels")
self.assertIn("wheels", str(cm.exception))
# ---------------------------------------------------------------------------
# get_artifacts_bucket_config_for_workflow_run
# ---------------------------------------------------------------------------
class TestGetArtifactsBucketConfigForWorkflowRun(unittest.TestCase):
"""Test the workflow-run-aware wrapper."""
def setUp(self):
self.api_patcher = mock.patch(
"github_actions.github_actions_api.gha_query_workflow_run_by_id"
)
self.mock_api = self.api_patcher.start()
self.env_patcher = mock.patch.dict(os.environ)
self.env_patcher.start()
os.environ.pop("GITHUB_REPOSITORY", None)
os.environ.pop("GITHUB_EVENT_NAME", None)
os.environ.pop("GITHUB_EVENT_PATH", None)
os.environ.pop("RELEASE_TYPE", None)
def tearDown(self):
self.env_patcher.stop()
self.api_patcher.stop()
def test_default_ci(self):
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock"
)
self.assertEqual(config.name, "therock-ci-artifacts")
def test_explicit_release_type(self):
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock", release_type="nightly"
)
self.assertEqual(config.name, "therock-nightly-artifacts")
def test_release_type_from_env(self):
os.environ["RELEASE_TYPE"] = "dev"
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock"
)
self.assertEqual(config.name, "therock-dev-artifacts")
def test_explicit_release_type_overrides_env(self):
os.environ["RELEASE_TYPE"] = "dev"
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock", release_type="nightly"
)
self.assertEqual(config.name, "therock-nightly-artifacts")
def test_workflow_run_same_repo(self):
fake_run = {
"id": 12345,
"head_repository": {"full_name": "ROCm/TheRock"},
}
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock", workflow_run=fake_run
)
self.assertEqual(config.name, "therock-ci-artifacts")
def test_workflow_run_from_fork(self):
fake_run = {
"id": 12345,
"head_repository": {"full_name": "SomeUser/TheRock"},
}
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock", workflow_run=fake_run
)
self.assertEqual(config.name, "therock-ci-artifacts-external")
# Fork PRs cannot assume an IAM role via OIDC (no trust relationship),
# so the wrapper must strip the role and fall back to runner base
# credentials. Regression coverage for #5654.
self.assertIsNone(config.iam_role)
self.assertIsNone(config.write_access_iam_role)
def test_workflow_run_external_repo_uses_oidc(self):
# An external (non-fork) repo such as rocm-libraries keeps the
# therock-ci-external role so it can authenticate via OIDC.
fake_run = {
"id": 12345,
"head_repository": {"full_name": "ROCm/rocm-libraries"},
}
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/rocm-libraries", workflow_run=fake_run
)
self.assertEqual(config.name, "therock-ci-artifacts-external")
self.assertEqual(config.iam_role, "therock-ci-external")
def test_workflow_run_same_repo_keeps_internal_role(self):
# A same-repo (non-fork) ROCm/TheRock PR is unaffected by the fork skip
# and keeps the internal therock-ci role.
fake_run = {
"id": 12345,
"head_repository": {"full_name": "ROCm/TheRock"},
}
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock", workflow_run=fake_run
)
self.assertEqual(config.name, "therock-ci-artifacts")
self.assertEqual(config.iam_role, "therock-ci")
def test_workflow_run_id_triggers_api_call(self):
self.mock_api.return_value = {
"id": 12345,
"head_repository": {"full_name": "ROCm/TheRock"},
}
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock", workflow_run_id="12345"
)
self.mock_api.assert_called_once_with("ROCm/TheRock", "12345")
self.assertEqual(config.name, "therock-ci-artifacts")
def _write_event(self, event: dict) -> str:
"""Write a synthetic GitHub event payload to a temp file.
Returns the path. Caller must os.unlink() after use.
Uses delete=False because NamedTemporaryFile(delete=True) holds an
exclusive lock on Windows, preventing the code under test from reading.
"""
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
json.dump(event, f)
return f.name
def test_fork_pr_from_event_payload(self):
"""Fork PR detected via event payload (no workflow_run dict)."""
event_path = self._write_event(
{"pull_request": {"head": {"repo": {"fork": True}}}}
)
try:
os.environ["GITHUB_EVENT_NAME"] = "pull_request"
os.environ["GITHUB_EVENT_PATH"] = event_path
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock"
)
self.assertEqual(config.name, "therock-ci-artifacts-external")
finally:
os.unlink(event_path)
def test_same_repo_pr_from_event_payload(self):
"""Same-repo PR detected via event payload (no workflow_run dict)."""
event_path = self._write_event(
{"pull_request": {"head": {"repo": {"fork": False}}}}
)
try:
os.environ["GITHUB_EVENT_NAME"] = "pull_request"
os.environ["GITHUB_EVENT_PATH"] = event_path
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock"
)
self.assertEqual(config.name, "therock-ci-artifacts")
finally:
os.unlink(event_path)
def test_workflow_run_id_ignored_when_workflow_run_provided(self):
"""workflow_run takes priority over workflow_run_id."""
fake_run = {
"id": 12345,
"head_repository": {"full_name": "ROCm/TheRock"},
}
config = get_artifacts_bucket_config_for_workflow_run(
github_repository="ROCm/TheRock",
workflow_run=fake_run,
workflow_run_id="99999",
)
self.mock_api.assert_not_called()
self.assertEqual(config.name, "therock-ci-artifacts")
if __name__ == "__main__":
unittest.main()