diff --git a/.buildkite/amd/scripts/bootstrap-amd-omni.sh b/.buildkite/amd/scripts/bootstrap-amd-omni.sh index 9eff6b6c7..60732d801 100755 --- a/.buildkite/amd/scripts/bootstrap-amd-omni.sh +++ b/.buildkite/amd/scripts/bootstrap-amd-omni.sh @@ -60,7 +60,8 @@ resolve_test_specs() { if ! selected_specs=$(python3 "$AMD_SUITE_SELECTOR" \ --branch "$BUILDKITE_BRANCH" \ --labels "$PR_LABELS" \ - --debug-test-yaml "${DEBUG_TEST_YAML:-}"); then + --debug-test-yaml "${DEBUG_TEST_YAML:-}" \ + --nightly "$NIGHTLY"); then exit 1 fi @@ -80,6 +81,12 @@ filter_test_specs_by_skip_ci() { case "$suite_spec" in READY_TESTS:*) level="l2" ;; MERGE_TESTS:*) level="l3" ;; + NIGHTLY_TESTS:*) + # Explicit PR and scheduled nightly selections must survive + # L2/L3 diff gating, including docs-only main commits. + runnable_specs+=("$suite_spec") + continue + ;; *) echo "ERROR: unknown AMD test suite spec '$suite_spec'" >&2 exit 1 @@ -101,7 +108,7 @@ filter_test_specs_by_skip_ci() { ":memo: CI skipped — docs or pytest skip-mark changes only" \ --style "info" 2>/dev/null || true fi - echo "No AMD L2/L3 suites remain after skip-ci filtering." + echo "No AMD suites remain after skip-ci filtering." exit 0 fi } @@ -219,8 +226,8 @@ if [[ $BUILDKITE_BRANCH == "main" ]]; then file_diff=$(get_diff_main) fi -# Resolve PR tier labels before skip-ci so ready and merge suites can be -# filtered independently for CI-YAML-only changes. +# Resolve PR tier labels before skip-ci so ready/merge suites can be filtered +# independently while an explicitly selected nightly suite passes through. resolve_test_specs filter_test_specs_by_skip_ci diff --git a/.buildkite/amd/scripts/select_test_suites.py b/.buildkite/amd/scripts/select_test_suites.py index b7c72f6e4..daed05bd3 100644 --- a/.buildkite/amd/scripts/select_test_suites.py +++ b/.buildkite/amd/scripts/select_test_suites.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project -"""Select AMD L2/L3 suites after Buildkite has created an AMD build. +"""Select AMD ready/merge/nightly suites after Buildkite creates a build. This repository-side selector does not decide which GitHub label events start the external ``vllm-omni-amd-ci`` pipeline. Its Buildkite PR build condition @@ -17,6 +17,7 @@ from collections.abc import Iterable SUITE_SPECS = { "ready": "READY_TESTS:test-amd-ready.yml", "merge": "MERGE_TESTS:test-amd-merge.yml", + "nightly": "NIGHTLY_TESTS:test-amd-nightly.yml", } @@ -28,7 +29,7 @@ def _parse_debug_suites(value: str) -> tuple[str, ...]: seen: set[str] = set() for suite in suites: if suite not in SUITE_SPECS: - raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge' or 'ready', got {suite!r}") + raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge', 'nightly', or 'ready', got {suite!r}") if suite in seen: raise ValueError(f"duplicate DEBUG_TEST_YAML suite {suite!r}") seen.add(suite) @@ -40,18 +41,27 @@ def select_amd_test_suites( branch: str, labels: Iterable[str], debug_test_yaml: str = "", + nightly: bool = False, ) -> tuple[str, ...]: """Return ordered suite names while preserving legacy unlabeled PRs.""" if debug_test_yaml: return _parse_debug_suites(debug_test_yaml) if branch == "main": - return ("merge",) + return ("nightly",) if nightly else ("merge",) label_set = {label.strip() for label in labels if label.strip()} - selected = tuple(suite for label, suite in (("ready", "ready"), ("merge-test", "merge")) if label in label_set) - # AMD historically uploaded L2 for every PR build. Keep that behavior for - # triggers such as amd-test while adding tier selection for ready/merge-test. + selected = tuple( + suite + for label, suite in ( + ("ready", "ready"), + ("merge-test", "merge"), + ("nightly-test", "nightly"), + ) + if label in label_set + ) + # AMD historically uploaded the ready suite for every admitted PR build. + # Preserve that fallback when no explicit tier label is present. return selected or ("ready",) @@ -60,6 +70,7 @@ def main() -> int: parser.add_argument("--branch", required=True) parser.add_argument("--labels", default="") parser.add_argument("--debug-test-yaml", default="") + parser.add_argument("--nightly", type=int, choices=(0, 1), default=0) args = parser.parse_args() labels = tuple(args.labels.splitlines()) @@ -68,19 +79,15 @@ def main() -> int: branch=args.branch, labels=labels, debug_test_yaml=args.debug_test_yaml, + nightly=bool(args.nightly), ) except ValueError as exc: parser.error(str(exc)) label_set = {label.strip() for label in labels if label.strip()} - if not args.debug_test_yaml and args.branch != "main" and not ({"ready", "merge-test"} & label_set): + if args.branch != "main" and not args.debug_test_yaml and not ({"ready", "merge-test", "nightly-test"} & label_set): print( - "No AMD L2/L3 tier label found; preserving the legacy ready-suite fallback.", - file=sys.stderr, - ) - if "nightly-test" in label_set: - print( - "AMD nightly-test has no suite yet and does not affect L2/L3 selection.", + "No AMD ready/merge/nightly label found; preserving the legacy ready-suite fallback.", file=sys.stderr, ) diff --git a/.buildkite/amd/test-amd-nightly.yml b/.buildkite/amd/test-amd-nightly.yml new file mode 100644 index 000000000..0da365d0c --- /dev/null +++ b/.buildkite/amd/test-amd-nightly.yml @@ -0,0 +1,66 @@ +# AMD MI300 `full_model` nightly coverage during burn-in. +# All jobs are non-blocking until the lane has stable runtime evidence. +# Historical build #11646 was red in Function Expansion and Accuracy (one +# async_chunk similarity mismatch; Seed-TTS WER 0.376480 > 0.35). + +env: + VLLM_WORKER_MULTIPROC_METHOD: spawn + HF_HUB_DOWNLOAD_TIMEOUT: 300 + HF_HUB_ETAG_TIMEOUT: 60 + +steps: + # MI325 is the repository's legacy ROCm pytest marker. The AMD template maps + # agent_pool to the current MI300 Buildkite queues independently of that mark. + - group: ":full_moon: Qwen3-Omni MI300 Nightly" + steps: + - label: "Qwen3-Omni Function Expansion" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 180 + commands: + - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" + - pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" + + - label: "Qwen3-Omni Accuracy" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 180 + artifact_paths: + - tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json + commands: + - export SEED_TTS_WER_EVAL=1 + # PyTorch ROCm uses the torch.cuda device namespace. + - export SEED_TTS_EVAL_DEVICE=cuda:1 + - pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" + # Native tests run from the image copy under /app/vllm-omni, while + # Buildkite's artifact hook searches the checkout workspace. + - | + if [[ "$$PWD" != "$${BUILDKITE_BUILD_CHECKOUT_PATH:?}" ]]; then + artifact_dir="$${BUILDKITE_BUILD_CHECKOUT_PATH}/tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc" + mkdir -p "$$artifact_dir" + cp -v tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json "$$artifact_dir/" + fi + + - label: "Qwen3-Omni Documentation Examples" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 120 + commands: + - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" + - pytest -s -v tests/examples/online_serving/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" + + - label: "Qwen3-Omni AITER-on Smoke" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 90 + commands: + - export VLLM_ROCM_USE_AITER=1 + - pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py::test_text_to_text_audio_001 -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" diff --git a/.buildkite/common/scripts/skip_ci.py b/.buildkite/common/scripts/skip_ci.py index 8d5fdd5e0..3b4168c01 100644 --- a/.buildkite/common/scripts/skip_ci.py +++ b/.buildkite/common/scripts/skip_ci.py @@ -44,6 +44,7 @@ L3_YAML_FILES: dict[str, str] = { L45_YAML_FILES: dict[str, str] = { ".buildkite/cuda/test-nightly.yml": "cuda", ".buildkite/cuda/test-weekly.yml": "cuda", + ".buildkite/amd/test-amd-nightly.yml": "amd", ".buildkite/npu/test-npu-nightly.yml": "npu", } diff --git a/docs/contributing/ci/ci_settings.md b/docs/contributing/ci/ci_settings.md index 9931a418d..4032891c0 100644 --- a/docs/contributing/ci/ci_settings.md +++ b/docs/contributing/ci/ci_settings.md @@ -35,6 +35,7 @@ Canonical layout (prefer these paths for new changes): ├── amd/ │ ├── test-amd-ready.yml # L2 job definitions (template input) │ ├── test-amd-merge.yml # L3 job definitions +│ ├── test-amd-nightly.yml # Nightly full-model jobs (experimental) │ ├── test-template-amd-omni.j2 # Renders final pipeline.yaml │ └── scripts/ │ ├── bootstrap-amd-omni.sh # Entry: skip-ci → Jinja → upload @@ -64,7 +65,7 @@ Canonical layout (prefer these paths for new changes): | -------- | ---------------- | -------------- | ---------------- | -------------------- | | **CUDA** | `cuda/pipeline.yml` | `test-ready.yml`, `test-merge.yml`, `test-nightly.yml`, `test-weekly.yml` | `upload_pipeline.py --upload` (expands uploader-only keys) | omit `mirror_hardwares` (from `-m`) / preset string + `MIRROR_HW` | | **NPU** | `npu/pipeline-npu.yml` | `test-npu-ready.yml`, `test-npu-nightly.yml` | `upload_pipeline.py --upload` | `mirror_hardwares: a2b3_npu_1` / `a2b3_npu_4` / `a3_npu_2` | -| **AMD** | `amd/scripts/bootstrap-amd-omni.sh` | `test-amd-ready.yml`, `test-amd-merge.yml` | Jinja (`test-template-amd-omni.j2`) → `pipeline upload` | `agent_pool` + `mirror_hardwares: [amdproduction]` (array, template filter) | +| **AMD** | `amd/scripts/bootstrap-amd-omni.sh` | `test-amd-ready.yml`, `test-amd-merge.yml`, `test-amd-nightly.yml` | Jinja (`test-template-amd-omni.j2`) → `pipeline upload` | `agent_pool` + `mirror_hardwares: [amdproduction]` (array, template filter) | | **Intel** | `intel/scripts/bootstrap-intel-omni.sh` | `intel/pipeline-intel.yml` (steps inline) | Direct `pipeline upload` | Inline `agents.queue` on each step | ## Platform configuration style @@ -171,9 +172,9 @@ Canonical layout (prefer these paths for new changes): **Bootstrap:** [`amd/scripts/bootstrap-amd-omni.sh`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/scripts/bootstrap-amd-omni.sh)—skip-ci, diff filtering, Jinja render, then `buildkite-agent pipeline upload`. - **Test YAML (data):** `amd/test-amd-ready.yml` (L2 / `ready`), `test-amd-merge.yml` (L3 / `merge-test` and `main`). On a PR carrying both labels, AMD combines both suites behind one image build. PR builds without either tier label retain the legacy L2 fallback for compatibility with the `amd-test` trigger. `DEBUG_TEST_YAML` remains an explicit override. AMD has no L4 file yet, so `nightly-test` does not select an additional suite. + **Test YAML (data):** `amd/test-amd-ready.yml` (L2 / `ready`), `test-amd-merge.yml` (L3 / `merge-test` and ordinary `main`), and experimental `test-amd-nightly.yml` (`full_model` / `nightly-test` or `main` with `NIGHTLY=1`). Multiple PR tier labels combine their suites behind one image build. PR builds that reach the bootstrap without a tier label retain the legacy ready-suite fallback. `DEBUG_TEST_YAML` accepts `ready`, `merge`, and `nightly` as an explicit override. During nightly burn-in every AMD nightly leaf is non-blocking. - **Trigger boundary:** AMD label handling has two layers. First, the external `vllm-omni-amd-ci` Buildkite pipeline condition decides whether a GitHub label event creates a build. Only after that build starts does this repository's bootstrap inspect all current PR labels and select L2, L3, or both. Repository-side selection therefore cannot make a `merge-test` event start AMD CI by itself. The external condition must admit both `ready` and `merge-test`, while preserving the legacy `amd-test` trigger and non-PR `main` / scheduled builds. For PR builds without a `DEBUG_TEST_YAML` override, an unreadable label set fails the bootstrap instead of silently selecting the wrong tier. Debug overrides skip label lookup and are validated directly; invalid values, including whitespace-only values, fail the bootstrap. Keep `nightly-test` out of the AMD condition until an AMD L4 suite exists; otherwise it would start a build without providing nightly coverage. + **Trigger boundary:** AMD label handling has two layers. First, the external `vllm-omni-amd-ci` Buildkite pipeline condition decides whether a GitHub label event creates a build. Only after that build starts does this repository's bootstrap inspect all current PR labels and select the ready, merge, nightly, or combined suites. Repository-side selection therefore cannot start AMD CI by itself. AMD-only nightly validation uses both `amd-test` and `nightly-test`: the external condition should accept an event for either label only when the complete PR label set contains both. `amd-test` admits the AMD pipeline, while `nightly-test` makes the bootstrap select `NIGHTLY_TESTS:test-amd-nightly.yml`. Existing `ready` / `merge-test` behavior and non-PR `main` / scheduled builds remain separate. For PR builds without a `DEBUG_TEST_YAML` override, an unreadable label set fails the bootstrap instead of silently selecting the wrong tier. Debug overrides skip label lookup and are validated directly; invalid values, including whitespace-only values, fail the bootstrap. Until the paired-label condition is configured, use an authorized manual Buildkite build with `DEBUG_TEST_YAML=nightly` and verify that the bootstrap reports only the nightly suite. **Rendering:** [`test-template-amd-omni.j2`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/test-template-amd-omni.j2) wraps data steps with `amd-build` image build and `amd_` queues. Do **not** hand-edit generated `pipeline.yaml`. @@ -189,7 +190,7 @@ Canonical layout (prefer these paths for new changes): **Adding a job** - 1. Edit `test-amd-ready.yml` or `test-amd-merge.yml`. + 1. Edit `test-amd-ready.yml`, `test-amd-merge.yml`, or `test-amd-nightly.yml`. 2. Copy a neighboring block: `label`, `agent_pool`, `mirror_hardwares`, `commands`, optional `grade`. 3. Regenerate via bootstrap / Jinja; update `skip_ci.py` if you add a new YAML path. @@ -245,7 +246,7 @@ Label triggers (`ready`, `merge-test`) are unchanged—diff-aware logic only red | Non-qualifying skip-mark and no CI YAML | normal CI | all on | | Diff unavailable | normal CI | all on | -**`skip_all` exceptions (CUDA/NPU bootstrap only):** PR labels (`nightly-test`, `merge-test`, `weekly-test`, `ready`, …) do **not** revive jobs under `skip_all`. On `main`, scheduled `NIGHTLY=1` still builds the image and uploads L4; `WEEKLY=1` or `NON_CRITICAL=1` still builds the image and uploads L5 (CUDA). `WEEKLY=1` on `main` also uploads L2/L3 with `--e2e`. +**`skip_all` exceptions:** For CUDA/NPU, PR labels (`nightly-test`, `merge-test`, `weekly-test`, `ready`, …) do **not** revive jobs under `skip_all`; on `main`, scheduled `NIGHTLY=1` still builds the image and uploads L4, while `WEEKLY=1` or `NON_CRITICAL=1` still builds the image and uploads L5 (CUDA). `WEEKLY=1` on `main` also uploads L2/L3 with `--e2e`. AMD applies `skip_ci.py gate` only to selected ready/merge specs, so an explicitly selected AMD nightly spec (`nightly-test`, `NIGHTLY=1`, or a nightly debug override) remains runnable even for a docs-only diff. **Yaml-gated nightly/weekly:** L4/L5 upload steps keep their normal label / `NIGHTLY` / `WEEKLY` / `NON_CRITICAL` conditions (for example PR `nightly-test` still uploads nightly). Only L2/L3 upload steps are matrix-gated. @@ -262,6 +263,7 @@ Register new files in `L2_YAML_FILES`, `L3_YAML_FILES`, or `L45_YAML_FILES` in ` | L3 | `.buildkite/cuda/test-merge.yml` | cuda | | L3 | `.buildkite/amd/test-amd-merge.yml` | amd | | L4/L5 | `.buildkite/cuda/test-nightly.yml`, `test-weekly.yml` | cuda | +| L4/L5 | `.buildkite/amd/test-amd-nightly.yml` | amd | | L4/L5 | `.buildkite/npu/test-npu-nightly.yml` | npu | ##### Yaml-gated category branches @@ -294,7 +296,7 @@ Docs/skip-mark mixed with any row below follows the same matrix. | CUDA ready + AMD merge | G4 | `cuda/l2` + `amd/l3` | | CUDA ready + AMD ready | G2 | `cuda/l2` + `amd/l2` | | CUDA merge + AMD merge | G3 | `cuda/l3` + `amd/l3` | -| Only nightly / weekly / npu-nightly YAML | G1 | (none) | +| Only nightly / weekly / amd-nightly / npu-nightly YAML | G1 | (none) | | CUDA ready + nightly | G5 | `cuda/l2` | | CUDA merge + nightly | G6 | `cuda/l3` | | CUDA ready + merge + nightly | G7 | `cuda/l2` + `cuda/l3` | diff --git a/docs/contributing/ci/test_system_overview.md b/docs/contributing/ci/test_system_overview.md index f432678bc..dde8f2a58 100644 --- a/docs/contributing/ci/test_system_overview.md +++ b/docs/contributing/ci/test_system_overview.md @@ -182,6 +182,8 @@ CUDA **L4** (`full_model`) jobs are defined once in [`.buildkite/cuda/test-night - **Nightly:** scheduled `main` builds with `NIGHTLY=1` (and PR labels such as `nightly-test` / `omni-test`). Default fleet is typically H100. - **Pre-release:** the same L4 suite runs again on extra GPU SKUs before a release (for example B200 via `MIRROR_HW=b200`), so `full_model` coverage is not limited to the nightly machine type. +AMD has an experimental, non-blocking `full_model` nightly vertical slice in [`.buildkite/amd/test-amd-nightly.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/amd/test-amd-nightly.yml). It selects ROCm Qwen3-Omni function-expansion, accuracy, documentation-example, and AITER-on smoke coverage on the MI300 pool. AMD-only PR validation uses `amd-test` to admit the external AMD pipeline and `nightly-test` to select this suite; scheduled `main` builds select it with `NIGHTLY=1`. Keep it non-blocking while the lane accumulates stability and completion-time evidence. + How count-form `mirror_hardwares` and `MIRROR_HW` pick a SKU: [CI Settings](./ci_settings.md). ### L2 / L3 diff-aware CI (CUDA) diff --git a/tests/buildkite/test_amd_bootstrap.py b/tests/buildkite/test_amd_bootstrap.py index 593ba8b26..ac0c8dba4 100644 --- a/tests/buildkite/test_amd_bootstrap.py +++ b/tests/buildkite/test_amd_bootstrap.py @@ -136,7 +136,7 @@ def test_label_lookup_selects_tiers(tmp_path, labels, expected_levels): ] == expected_levels -@pytest.mark.parametrize("debug_test_yaml", ["ready,ready", "nightly", ", ,", " \t"]) +@pytest.mark.parametrize("debug_test_yaml", ["ready,ready", "nightly,nightly", ", ,", " \t"]) def test_invalid_debug_override_fails_without_label_lookup(tmp_path, debug_test_yaml): result = _run_bootstrap(tmp_path, debug_test_yaml=debug_test_yaml, curl_status=22) diff --git a/tests/buildkite/test_amd_pipeline.py b/tests/buildkite/test_amd_pipeline.py index 1e74b50a1..c2c45f5ef 100644 --- a/tests/buildkite/test_amd_pipeline.py +++ b/tests/buildkite/test_amd_pipeline.py @@ -10,10 +10,11 @@ import yaml pytestmark = [pytest.mark.core_model, pytest.mark.cpu] AMD_MERGE_PIPELINE = Path(".buildkite/amd/test-amd-merge.yml") +AMD_NIGHTLY_PIPELINE = Path(".buildkite/amd/test-amd-nightly.yml") -def _find_step(label: str) -> dict: - pipeline = yaml.safe_load(AMD_MERGE_PIPELINE.read_text(encoding="utf-8")) +def _find_step(label: str, pipeline_path: Path = AMD_MERGE_PIPELINE) -> dict: + pipeline = yaml.safe_load(pipeline_path.read_text(encoding="utf-8")) def walk(steps: list[dict]) -> dict | None: for step in steps: @@ -40,3 +41,15 @@ def test_qwen3_tts_base_preserves_advanced_model_arguments() -> None: run_level_index = argv.index("--run-level") assert argv[marker_index + 1] == "advanced_model and cuda" assert argv[run_level_index + 1] == "advanced_model" + + +def test_qwen3_accuracy_defers_artifact_path_expansion() -> None: + step = _find_step("Qwen3-Omni Accuracy", AMD_NIGHTLY_PIPELINE) + staging_command = next(command for command in step["commands"] if "artifact_dir=" in command) + + # Dynamic pipelines are interpolated once during upload. Double dollars + # preserve these variables for the GPU job's runtime shell. + assert '"$$PWD"' in staging_command + assert '"$${BUILDKITE_BUILD_CHECKOUT_PATH:?}"' in staging_command + assert '"$$artifact_dir"' in staging_command + assert step["artifact_paths"] == ["tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json"] diff --git a/tests/buildkite/test_amd_suite_selection.py b/tests/buildkite/test_amd_suite_selection.py index b1b25aa26..dc447f208 100644 --- a/tests/buildkite/test_amd_suite_selection.py +++ b/tests/buildkite/test_amd_suite_selection.py @@ -24,10 +24,12 @@ SPEC.loader.exec_module(SELECTOR) ("feature", ("ready",), ("ready",)), ("feature", ("merge-test",), ("merge",)), ("feature", ("merge-test", "ready"), ("ready", "merge")), + ("feature", ("nightly-test",), ("nightly",)), + ("feature", ("ready", "merge-test", "nightly-test"), ("ready", "merge", "nightly")), ("feature", ("amd-test",), ("ready",)), ("feature", ("amd-test", "merge-test"), ("merge",)), ("feature", ("amd-test", "ready", "merge-test"), ("ready", "merge")), - ("feature", ("nightly-test",), ("ready",)), + ("feature", ("amd-test", "nightly-test"), ("nightly",)), ("feature", ("not-ready", "merge-test-extra"), ("ready",)), ], ) @@ -39,8 +41,17 @@ def test_debug_override_takes_precedence_and_normalizes_input(): assert SELECTOR.select_amd_test_suites( branch="main", labels=("ready",), - debug_test_yaml=" MERGE, ready,", - ) == ("merge", "ready") + debug_test_yaml=" NIGHTLY, merge, ready,", + nightly=False, + ) == ("nightly", "merge", "ready") + + +def test_scheduled_main_selects_only_nightly(): + assert SELECTOR.select_amd_test_suites( + branch="main", + labels=(), + nightly=True, + ) == ("nightly",) def test_empty_debug_override_uses_normal_selection(): @@ -51,7 +62,7 @@ def test_empty_debug_override_uses_normal_selection(): ) == ("merge",) -@pytest.mark.parametrize("value", ["ready,ready", "nightly", ", ,", " \t"]) +@pytest.mark.parametrize("value", ["ready,ready", "nightly,nightly", "weekly", ", ,", " \t"]) def test_invalid_debug_override(value): with pytest.raises(ValueError): SELECTOR.select_amd_test_suites( diff --git a/tests/buildkite/test_skip_ci.py b/tests/buildkite/test_skip_ci.py index 4c90b3ff7..1a04ecab8 100644 --- a/tests/buildkite/test_skip_ci.py +++ b/tests/buildkite/test_skip_ci.py @@ -144,6 +144,14 @@ def test_npu_nightly_only_skips_all_l23() -> None: assert not decision.is_run("npu", "l3") +def test_amd_nightly_only_skips_all_l23() -> None: + decision = _decision([".buildkite/amd/test-amd-nightly.yml"]) + assert _is_yaml_gated(decision) + assert _all_l23_skipped(decision) + assert not decision.is_run("amd", "l2") + assert not decision.is_run("amd", "l3") + + def test_nightly_and_weekly_skips_all_l23() -> None: decision = _decision( [