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
307 lines
12 KiB
Python
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()
|