# Nightly CI Test This document explains how to trigger nightly hardware CI tests against your own PR code on Ascend NPU hardware (A2/A3), without waiting for the scheduled nightly run. ## Background By default, nightly CI tests run on a fixed schedule using pre-built nightly images. Contributors can self-service trigger these tests directly against their PR changes by combining a GitHub label with a comment command. ## How to Trigger ### 1. Post a comment Post one of the following comments in the PR to specify which tests to run. The comment itself triggers the workflow — no label is required. | Comment | Effect | |---------|--------| | `/nightly` | Run **all** nightly tests | | `/nightly all` | Run **all** nightly tests (same as above) | | `/nightly test1 test2 ...` | Run only the **named** tests | :::{note} Only repository **Contributors** (Triage role) and **Maintainers** (Write role) can trigger the `/nightly` command. If you do not have this permission, ask a maintainer to post the comment for you. You can find the list of maintainers and contributors in the project's [Governance](../../community/governance.md) page or by checking the [CODEOWNERS](https://github.com/vllm-project/vllm-ascend/blob/main/.github/CODEOWNERS) file. ::: ### 2. Wait for results GitHub Actions will trigger the `Nightly-A2` or `Nightly-A3` workflow. Only tests matching the filter will be dispatched, which saves hardware resources. ## Differences Between PR and Scheduled Runs | | Scheduled / Manual Dispatch | PR-triggered | |---|----------------------------|---| | Trigger | Cron (daily) or `workflow_dispatch` | `/nightly` comment | | Code tested | Pre-built nightly image | Your PR's HEAD commit (source installed fresh) | | Test scope | All tests | Configurable via `/nightly ` | | vLLM + vllm-ascend | From image | Checked out and installed from source | | Test matrix | From main branch's matrix YAML | From PR branch's matrix YAML | When a PR run is detected (`is_pr_test: true`), the workflow additionally: 1. Uninstalls any existing vllm packages in the container. 2. Checks out the specific vllm version and your PR's vllm-ascend commit from source. 3. Installs all dependencies from source. 4. Installs the `aisbench` benchmark suite. ## Test Matrix Data Source The set of nightly test cases (their names, runners, test paths, model configs) is declared in a single data file: ```text .github/workflows/configs/nightly_config.yaml ``` The file is organized as `a2:` and `a3:` top-level keys (one per SoC). Under each SoC, tests are grouped by execution shape (single-node, multi-node, double-node, multi-card, accuracy) and each group holds a `test_config` (or `nightly` / `pr_only` for accuracy) list whose entries carry a `name` plus the fields consumed by the downstream reusable workflows (`os`, `tests`, `config_file_path`, `size`, etc.). Both the `Nightly-A2` and `Nightly-A3` workflows dynamically read this file at run time — there is no hardcoded test matrix in the workflow YAMLs. The `/nightly ` slash command resolves names by walking the same file from the PR branch, so newly added entries can be exercised on a PR before they land on main. ## Adding a New Nightly Test Case To add a new test case (no need to touch the workflow YAMLs): 1. Append an entry under the appropriate section in `.github/workflows/configs/nightly_config.yaml`. Each entry needs at least: - `name`: unique identifier used in `/nightly ` filters - `os` (for single-node / multi-card pytest+yaml tests) or `runner` is inferred - one of `tests:` (pytest directory) or `config_file_path:` (YAML-driven model config) - `size` (multi-node / double-node only) 2. Add the actual test files (pytest modules under `tests/e2e/nightly/...` or YAML model configs in `tests/e2e/nightly/.../configs/`). 3. Open a PR. Once CI is green, you can validate the new entry against real NPU hardware **without** merging the PR — see *Examples* below. ## Available Test Names The test names you can pass to `/nightly` correspond to the `name` fields under the matching section in `.github/workflows/configs/nightly_config.yaml`. The tables below mirror the current contents of that file. ### A2 workflow (`.github/workflows/schedule_nightly_test_a2.yaml`) **Single-node tests** (`a2.single_node.test_config`): | Test name | Description | |-----------|-------------| | `test_custom_op_multi_card` | Custom operator tests (multi card) | | `qwen3-vl-32b-instruct-w8a8` | Qwen3-VL-32B-Instruct W8A8 | | `qwen3-32b-int8` | Qwen3-32B INT8 quantization | | `Qwen3.5-27B-w8a8-A2` | Qwen3.5-27B W8A8 | | `Qwen3.5-397B-A17B-w4a8-mtp` | Qwen3.5-397B-A17B W4A8 + MTP | **Multi-node tests** (`a2.multi_node.test_config`): | Test name | Description | |-----------|-------------| | `multi-node-qwen3-235b-dp` | Qwen3-235B-A22B, 2-node DP | | `multi-node-GLM-5.1-w8a8-A2` | GLM-5.1 W8A8, 2 nodes | | `multi-node-Kimi-K2.5-W4A8-A2` | Kimi-K2.5 W4A8, 2 nodes | **Accuracy tests** (`a2.accuracy.nightly` and `a2.accuracy.pr_only`): | Test name | Description | Scope | |-----------|-------------|-------| | `accuracy-group-1` | Qwen3-VL-8B, Qwen3-8B, Qwen2-Audio-7B, etc. | nightly | | `accuracy-group-2` | ERNIE-4.5, Molmo-7B, Llama-3.2-3B, etc. | nightly | | `accuracy-group-3` | Qwen3-30B-A3B, Qwen3-VL-30B-A3B, etc. | nightly | | `accuracy-group-4` | Qwen3-Next-80B-A3B, Qwen3-Omni-30B-A3B, etc. | nightly | | `pr-accuracy-group-1` | gemma-3-4b-it, internlm3-8b-instruct, etc. | pr_only | | `pr-accuracy-group-2` | Qwen2.5-Math-RM-72B, Hunyuan-A13B-Instruct | pr_only | The `pr-accuracy-group-*` entries only run on `/nightly` (PR-triggered) runs; `/nightly all` on the schedule skips them. ### A3 workflow (`.github/workflows/schedule_nightly_test_a3.yaml`) **Multi-node tests** (`a3.multi_node.test_config`, 4-node): | Test name | Description | |-----------|-------------| | `multi-node-deepseek-v3.2-W8A8-EP` | DeepSeek-V3.2-W8A8 with EP, 4-node | **Double-node tests** (`a3.double_node.test_config`, 2-node, run after multi-node): | Test name | Description | |-----------|-------------| | `multi-node-deepseek-r1-w8a8-longseq` | DeepSeek-R1-W8A8 long sequence, 2-node | | `multi-node-qwen3-dp` | Qwen3-235B-A22B, 2-node DP | | `multi-node-qwenw8a8-2node-eplb` | Qwen3-235B-W8A8 with EPLB, 2-node | | `multi-node-dpsk3.2-2node` | DeepSeek-V3.2-W8A8, 2-node | | `multi-node-qwenw8a8-2node-longseq` | Qwen3-235B-W8A8 long sequence, 2-node | | `multi-node-qwen-disagg-pd` | Qwen3-235B disaggregated PD, 2-node | | `multi-node-qwen-vl-disagg-pd` | Qwen3-VL-235B disaggregated PD, 2-node | | `multi-node-deepseek-v3.1` | DeepSeek-V3.1-BF16, 2-node | | `multi-node-deepseek-v3.2-W8A8-EP` | DeepSeek-V3.2-W8A8 with EP, 4-node | | `multi-node-glm-5.2` | GLM-5.1-W8A8, 2-node | **Single-node tests** (`a3.single_node.test_config`): | Test name | Description | |-----------|-------------| | `mtpx-deepseek-r1-0528-w8a8` | MTP-X + DeepSeek-R1-0528-W8A8 | | `deepseek-r1-0528-w8a8` | DeepSeek-R1-0528-W8A8 | | `kimi-k2-thinking` | Kimi-K2-Thinking | | `qwen3-vl-235b-a22b-instruct-w8a8` | Qwen3-VL-235B-A22B-Instruct-W8A8 | | `deepseek-r1-0528-w8a8-prefix-cache` | DeepSeek-R1-0528-W8A8 prefix cache | | `deepseek-v3-2-w8a8` | DeepSeek-V3.2-W8A8 | | `glm-4.7-w8a8` | GLM-4.7 W8A8 | | `kimi-k2.5` | Kimi-K2.5 | | `qwen3-235b-a22b-w8a8` | Qwen3-235B-A22B-W8A8 | | `Qwen3.5-397B-A17B-w8a8-mtp` | Qwen3.5-397B-A17B W8A8 + MTP | | `MiniMax-M2.5-w8a8-QuaRot-A3` | MiniMax-M2.5 W8A8 + QuaRot | | `Qwen3.5-27B-w8a8-A3` | Qwen3.5-27B W8A8 | | `Qwen3.5-122B-A10B-W8A8-A3` | Qwen3.5-122B-A10B W8A8 | | `DeepSeek-V4-Flash-W8A8-A3` | DeepSeek-V4-Flash W8A8 | **Multi-card tests** (`a3.multi_card.test_config`): | Test name | Description | |-----------|-------------| | `qwen3-30b-acc` | Qwen3-30B accuracy test | | `qwen3-30b-a3b-w8a8` | Qwen3-30B-A3B-W8A8 | | `qwen3-32b-int8` | Qwen3-32B-Int8 | | `qwen3-32b-int8-prefix-cache` | Qwen3-32B-Int8 prefix cache | | `Qwen3-30B-A3B-W4A8-llm-compressor` | Qwen3-30B-A3B W4A8 via llm-compressor | | `Qwen3-30B-QuaRot` | Qwen3-30B QuaRot + eagle3 | | `Qwen3-32B-QuaRot` | Qwen3-32B QuaRot + eagle3 | :::{warning} The A3 resource pool has a maximum concurrency of **5×16 NPUs**. Multi-node tests run with `max-parallel: 2` to avoid resource exhaustion. Running `/nightly all` on A3 will queue a large number of jobs — prefer targeting specific test names when possible. ::: ## Examples Run all available nightly tests against your PR: ```text /nightly ``` Run only the custom operator multi-card test: ```text /nightly test_custom_op_multi_card ``` Run two specific tests at once (one per SoC): ```text /nightly test_custom_op_multi_card mtpx-deepseek-r1-0528-w8a8 ``` Run a single accuracy group (with all of its models): ```text /nightly accuracy-group-1 ``` Run a single accuracy model (only that model from a group): ```text /nightly accuracy-group-1/Qwen3-8B ``` Re-trigger after fixing an issue: just push a new commit. The `synchronize` event re-runs the workflow and picks up the existing `/nightly` comment automatically — no need to post a new comment. ## Adding a New Test Case — Worked Example To add `my-new-test` to the A2 single-node section: 1. Edit `.github/workflows/configs/nightly_config.yaml`, append under `a2.single_node.test_config`: ```yaml - name: my-new-test os: linux-aarch64-a2b3-4 tests: tests/e2e/nightly/single_node/ops/multicard_ops_a2/test_my_new.py ``` 2. Commit the new pytest file (`test_my_new.py`) in the same PR. 3. Trigger from the PR: ```text /nightly my-new-test ``` The workflow will: - `pr_nightly_command.yml` reads your PR's `nightly_config.yaml` and resolves `my-new-test` → dispatch A2 only. - `Nightly-A2` is dispatched at `main`, but `generate-a2-matrix` checks out your PR commit and reads the new entry from the matrix. - `single-node-tests` runs one matrix job for `my-new-test`, with `should_run=true`. The reusable workflow checks out your PR code (via `vllm_ascend_ref`) and runs your pytest. ## Troubleshooting **The workflow didn't start after I posted the comment.** - Check that the comment starts exactly with `/nightly` with no leading spaces or extra characters before the slash. - Confirm you have at least Triage permission on the repository; unauthorized users' comments are ignored. - To re-trigger after fixing an issue, simply push a new commit — the workflow will reuse the existing `/nightly` comment automatically. **Only some tests ran, not the ones I expected.** - Test names are case-sensitive and must match the `name` field in `.github/workflows/configs/nightly_config.yaml` exactly (see the tables above). - For a PR-triggered run, the matrix is loaded from your PR's `nightly_config.yaml`, not main. If a name isn't in your PR's file, it won't be recognized and the dispatch will be skipped. - Check the `parse-trigger` job output in GitHub Actions for the resolved `test_filter` value. **The workflow ran with the scheduled image, not my PR code.** - Confirm the workflow was triggered by `repository_dispatch` (slash command), not bare `workflow_dispatch`. The `pr_nightly_command.yml` workflow is what actually dispatches `schedule_nightly_test_a2.yaml` / `_a3.yaml` with `vllm_ascend_ref` pointing at your PR SHA. **A new test I added isn't being recognized.** - Confirm the entry is well-formed YAML under `.github/workflows/configs/nightly_config.yaml`. The `name` field is required and must be unique within the SoC's section. - The matrix is loaded from your PR branch, so make sure the file is committed to the same branch the `/nightly` comment was posted on. **How to obtain more detailed logs to pinpoint problems for multi-node tests** - For most issues, the stdout pop-up logs from GitHub actions are sufficient (this log always represents the logs from the first node). - If the logs from a first node are no longer sufficient to provide effective logging information, see the summary of your jobs to download log archive for the corresponding test, which includes the framework-side logs and plog information for each node, structured as follows: ```shell . ├── node0 │ ├── root │ │ └── ascend │ │ └── log │ └── var │ └── log │ └── vllm-deepseek-v3-0f233d-0_logs.txt └── node1 ├── root │ └── ascend │ └── log └── var └── log └── vllm-deepseek-v3-0f233d-0-1_logs.txt ```