2727 required : false
2828 type : string
2929 default : ' '
30- description : JSON array of test files to ignore (e.g., '["tests/unit_tests/test_a.py", "tests/unit_tests/test_b.py"]')
30+ description : JSON array of test files to ignore
3131
3232jobs :
33- # Detect which test groups need to run based on changed files
33+ # 1. Change Detection: Monitors both new unit tests and legacy QA paths
3434 detect_changes :
3535 runs-on : ubuntu-latest
3636 outputs :
3737 core : ${{ steps.filter.outputs.core }}
38- transformer : ${{ steps.filter.outputs.transformer }}
39- models : ${{ steps.filter.outputs.models }}
40- distributed : ${{ steps.filter.outputs.distributed }}
41- dist_checkpointing : ${{ steps.filter.outputs.dist_checkpointing }}
42- tensor_parallel : ${{ steps.filter.outputs.tensor_parallel }}
43- pipeline_parallel : ${{ steps.filter.outputs.pipeline_parallel }}
44- data : ${{ steps.filter.outputs.data }}
45- fusions : ${{ steps.filter.outputs.fusions }}
46- others : ${{ steps.filter.outputs.others }}
38+ qa_l0 : ${{ steps.filter.outputs.qa_l0 }}
4739 steps :
4840 - name : Checkout source code
49- uses : actions/checkout@v6
41+ uses : actions/checkout@v4
5042 with :
5143 fetch-depth : 0
5244
5345 - name : Detect changed paths
5446 id : filter
5547 run : |
5648 set -euo pipefail
57-
58- # Get the base ref for comparison
59- if [ "${{ github.event_name }}" == "pull_request" ]; then
60- BASE_REF="origin/${{ github.base_ref }}"
61- git fetch origin ${{ github.base_ref }} --depth=1
62- else
63- # For push events, compare with the previous commit
64- BASE_REF="HEAD~1"
65- fi
66- # Get list of changed files
49+ # Identify base reference for diff
50+ BASE_REF="${{ github.event_name == 'pull_request' && format('origin/{0}', github.base_ref) || 'HEAD~1' }}"
51+ [ "${{ github.event_name }}" == "pull_request" ] && git fetch origin ${{ github.base_ref }} --depth=1
52+
6753 CHANGED_FILES=$(git diff --name-only $BASE_REF...HEAD 2>/dev/null || git diff --name-only $BASE_REF HEAD)
6854
69- # Function to check if any pattern matches
70- check_patterns() {
71- local patterns="$1"
72- for pattern in $patterns; do
73- if echo "$CHANGED_FILES" | grep -qE "$pattern"; then
74- echo "true"
75- return
76- fi
77- done
78- echo "false"
79- }
80-
81- # Core tests: root-level test files and core megatron files
82- CORE_PATTERNS="^tests/unit_tests/test_.*\.py$ ^megatron/core/[^/]*\.py$ ^megatron/core/__init__\.py$"
83- echo "core=$(check_patterns "$CORE_PATTERNS")" >> $GITHUB_OUTPUT
84-
85- # Transformer tests
86- TRANSFORMER_PATTERNS="^tests/unit_tests/transformer/ ^megatron/core/transformer/"
87- echo "transformer=$(check_patterns "$TRANSFORMER_PATTERNS")" >> $GITHUB_OUTPUT
88-
89- # Models tests
90- MODELS_PATTERNS="^tests/unit_tests/models/ ^megatron/core/models/"
91- echo "models=$(check_patterns "$MODELS_PATTERNS")" >> $GITHUB_OUTPUT
92-
93- # Distributed tests
94- DISTRIBUTED_PATTERNS="^tests/unit_tests/distributed/ ^megatron/core/distributed/"
95- echo "distributed=$(check_patterns "$DISTRIBUTED_PATTERNS")" >> $GITHUB_OUTPUT
96-
97- # Dist checkpointing tests
98- DIST_CKPT_PATTERNS="^tests/unit_tests/dist_checkpointing/ ^megatron/core/dist_checkpointing/"
99- echo "dist_checkpointing=$(check_patterns "$DIST_CKPT_PATTERNS")" >> $GITHUB_OUTPUT
100-
101- # Tensor parallel tests
102- TP_PATTERNS="^tests/unit_tests/tensor_parallel/ ^megatron/core/tensor_parallel/"
103- echo "tensor_parallel=$(check_patterns "$TP_PATTERNS")" >> $GITHUB_OUTPUT
104-
105- # Pipeline parallel tests
106- PP_PATTERNS="^tests/unit_tests/pipeline_parallel/ ^megatron/core/pipeline_parallel/"
107- echo "pipeline_parallel=$(check_patterns "$PP_PATTERNS")" >> $GITHUB_OUTPUT
108-
109- # Data tests
110- DATA_PATTERNS="^tests/unit_tests/data/ ^megatron/core/datasets/"
111- echo "data=$(check_patterns "$DATA_PATTERNS")" >> $GITHUB_OUTPUT
112-
113- # Fusions tests
114- FUSIONS_PATTERNS="^tests/unit_tests/fusions/ ^megatron/core/fusions/"
115- echo "fusions=$(check_patterns "$FUSIONS_PATTERNS")" >> $GITHUB_OUTPUT
116-
117- # Others tests (export, post_training, tokenizers, utils)
118- OTHERS_PATTERNS="^tests/unit_tests/export/ ^tests/unit_tests/post_training/ ^tests/unit_tests/tokenizers/ ^tests/unit_tests/utils/ ^megatron/core/export/ ^megatron/post_training/ ^megatron/tokenizer/ ^megatron/core/utils/"
119- echo "others=$(check_patterns "$OTHERS_PATTERNS")" >> $GITHUB_OUTPUT
120-
121- echo "=== Change detection complete ==="
55+ # Logic for core framework and new pytest suite
56+ echo "core=$(echo "$CHANGED_FILES" | grep -qE "^tests/unit_tests/|^megatron/core/" && echo "true" || echo "false")" >> $GITHUB_OUTPUT
57+ # Logic for legacy QA L0 scripts and PyTorch specific paths
58+ echo "qa_l0=$(echo "$CHANGED_FILES" | grep -qE "^qa/L0_|^transformer_engine/|^tests/pytorch/" && echo "true" || echo "false")" >> $GITHUB_OUTPUT
12259
60+ # 2. Unified Test Execution: Supports both pytest and legacy shell scripts
12361 unit_test :
12462 needs : detect_changes
12563 defaults :
@@ -130,153 +68,112 @@ jobs:
13068 fail-fast : false
13169 matrix :
13270 test_group :
71+ # Modern Pytest architecture
13372 - name : core
13473 path : " tests/unit_tests/test_*.py"
135- description : " Core unit tests"
136- - name : transformer
137- path : " tests/unit_tests/transformer/"
138- description : " Transformer tests"
139- - name : models
140- path : " tests/unit_tests/models/"
141- description : " Model tests"
74+ test_type : " pytest"
14275 - name : distributed
14376 path : " tests/unit_tests/distributed/"
144- description : " Distributed tests"
145- - name : dist_checkpointing
146- path : " tests/unit_tests/dist_checkpointing/"
147- description : " Distributed checkpointing tests"
148- - name : tensor_parallel
149- path : " tests/unit_tests/tensor_parallel/"
150- description : " Tensor parallel tests"
151- - name : pipeline_parallel
152- path : " tests/unit_tests/pipeline_parallel/"
153- description : " Pipeline parallel tests"
154- - name : data
155- path : " tests/unit_tests/data/"
156- description : " Data tests"
157- - name : fusions
158- path : " tests/unit_tests/fusions/"
159- description : " Fusion tests"
160- - name : others
161- path : " tests/unit_tests/export/ tests/unit_tests/post_training/ tests/unit_tests/tokenizers/ tests/unit_tests/utils/"
162- description : " Other tests (a2a_overlap, export, post_training, tokenizers, utils)"
77+ test_type : " pytest"
78+
79+ # Integrated legacy QA L0 groups
80+ - name : pytorch_unittest
81+ path : " qa/L0_pytorch_unittest/test.sh"
82+ test_type : " sh"
83+ - name : pytorch_debug
84+ path : " qa/L0_pytorch_debug_unittest/test.sh"
85+ test_type : " sh"
86+ - name : pytorch_lint
87+ path : " qa/L0_pytorch_lint/test.sh"
88+ test_type : " sh"
89+ - name : pytorch_wheel
90+ path : " qa/L0_pytorch_wheel/test.sh"
91+ test_type : " sh"
92+
16393 name : unit-${{ inputs.device }}-${{ matrix.test_group.name }}
16494 container :
16595 image : ${{ inputs.image }}
166-
16796 ports :
16897 - 80
16998 volumes : ${{ fromJson(inputs.container_volumes) }}
170- # options: ${{ inputs. container_options }}
99+ # Crucial: --pull never prevents internet access; container_options should include --privileged
171100 options : --pull never ${{ inputs.container_options }}
101+
172102 steps :
173- # Check if this test group should run based on changed files or "full ci" label
174103 - name : Check if tests should run
175104 id : should_run
176105 run : |
177- TEST_GROUP ='${{ matrix.test_group.name }}'
106+ GROUP ='${{ matrix.test_group.name }}'
178107 FULL_CI='${{ contains(github.event.pull_request.labels.*.name, 'full ci') }}'
179-
180- # If "full ci" label is present, run all tests
181- if [ "$FULL_CI" == "true" ]; then
182- echo "should_run=true" >> $GITHUB_OUTPUT
183- exit 0
108+
109+ if [ "$FULL_CI" == "true" ]; then
110+ echo "should_run=true" >> $GITHUB_OUTPUT; exit 0
184111 fi
185112
186- # Check change detection output for this test group
187- case "$TEST_GROUP" in
188- core) CHANGED='${{ needs.detect_changes.outputs.core }}' ;;
189- transformer) CHANGED='${{ needs.detect_changes.outputs.transformer }}' ;;
190- models) CHANGED='${{ needs.detect_changes.outputs.models }}' ;;
191- distributed) CHANGED='${{ needs.detect_changes.outputs.distributed }}' ;;
192- dist_checkpointing) CHANGED='${{ needs.detect_changes.outputs.dist_checkpointing }}' ;;
193- tensor_parallel) CHANGED='${{ needs.detect_changes.outputs.tensor_parallel }}' ;;
194- pipeline_parallel) CHANGED='${{ needs.detect_changes.outputs.pipeline_parallel }}' ;;
195- data) CHANGED='${{ needs.detect_changes.outputs.data }}' ;;
196- fusions) CHANGED='${{ needs.detect_changes.outputs.fusions }}' ;;
197- others) CHANGED='${{ needs.detect_changes.outputs.others }}' ;;
198- *) CHANGED="true" ;;
199- esac
200-
113+ if [[ "$GROUP" == "pytorch_"* ]]; then
114+ CHANGED='${{ needs.detect_changes.outputs.qa_l0 }}'
115+ else
116+ CHANGED='${{ needs.detect_changes.outputs.core }}'
117+ fi
201118 echo "should_run=$CHANGED" >> $GITHUB_OUTPUT
202-
203119
204120 - name : Checkout source code
205121 if : steps.should_run.outputs.should_run == 'true'
206- uses : actions/checkout@v6
122+ uses : actions/checkout@v4
207123 with :
208- repository : ${{ github.event.pull_request.head.repo.full_name || github.repository }}
209- ref : ${{ github.event.pull_request.head.ref || github.ref }}
210- ssh-strict : true
211- ssh-user : git
212- ssh-key : ${{ secrets.RUNNER_SSH_KEY }}
213- persist-credentials : false
214- clean : true
215- sparse-checkout-cone-mode : true
216- fetch-tags : false
217- show-progress : true
218- lfs : false
219-
220- - name : Set safe directory
221- if : steps.should_run.outputs.should_run == 'true'
222- run : |
223- git config --global --add safe.directory $GITHUB_WORKSPACE
124+ set-safe-directory : true
224125
225- - name : Setup Python environment
126+ - name : Metax Environment Setup
226127 if : steps.should_run.outputs.should_run == 'true'
227- working-directory : ${{ github.workspace }}
228128 run : |
229129 set -euo pipefail
230- echo "Python location: $(which python)"
231- echo "Python version: $(python --version)"
232- # Install package in development mode
233- pip install boto3==1.42.1
130+ # Dynamically set MACA library path if drivers are mounted
131+ if [ -d "/usr/local/maca/lib" ]; then
132+ echo "Setting MACA library path..."
133+ echo "LD_LIBRARY_PATH=/usr/local/maca/lib:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV
134+ fi
135+
136+ # Install dependencies required by legacy QA scripts
137+ pip install --no-cache-dir transformers expecttest boto3==1.42.1
138+ # Install current repo in editable mode without re-building
234139 pip install -e . --no-deps
235- timeout-minutes : 30
140+ timeout-minutes : 20
236141
237- - name : Run unit tests - ${{ matrix.test_group.name }}
142+ - name : Execute Tests
238143 if : steps.should_run.outputs.should_run == 'true'
239- id : unit_test
240144 working-directory : ${{ github.workspace }}
241145 run : |
242146 set -euo pipefail
243-
244- PLATFORM='${{ inputs.platform }}'
245- DEVICE='${{ inputs.device }}'
246- TEST_GROUP='${{ matrix.test_group.name }}'
247- TEST_PATH='${{ matrix.test_group.path }}'
248-
249- echo "Running unit tests: $TEST_GROUP"
250- echo "Test path: $TEST_PATH"
251- echo "Platform: $PLATFORM"
252- echo "Device: $DEVICE"
253-
254- # Set environment variables
147+
148+ # Base environment variables (required for legacy scripts)
149+ export TE_PATH=$GITHUB_WORKSPACE
255150 export PYTHONPATH=$GITHUB_WORKSPACE:${PYTHONPATH:-}
256- export TORCHINDUCTOR_CACHE_DIR=/tmp/.torch_inductor_cache
257- mkdir -p $TORCHINDUCTOR_CACHE_DIR
258-
259- # Build ignore options from ignored_tests input
260- IGNORED_TESTS='${{ inputs.ignored_tests }}'
261- IGNORE_OPTS=""
262- if [ -n "$IGNORED_TESTS" ] && [ "$IGNORED_TESTS" != "[]" ]; then
263- echo "Parsing ignored tests list..."
264- # Parse JSON array and build --ignore options
265- IGNORE_OPTS=$(echo "$IGNORED_TESTS" | python3 -c "import sys, json; tests = json.load(sys.stdin); print(' '.join(['--deselect=' + t for t in tests])) if tests else None")
266- if [ -n "$IGNORE_OPTS" ]; then
267- echo "Ignoring tests: $IGNORE_OPTS"
151+ export RUN_LOG=/tmp/te_logs && mkdir -p $RUN_LOG
152+
153+ # Detect local GPU count dynamically (e.g., 2 for C500)
154+ NUM_GPUS=$(python3 -c "import torch; print(torch.cuda.device_count() if torch.cuda.is_available() else 0)")
155+ echo "=== Detected $NUM_GPUS GPUs, starting execution ==="
156+
157+ if [ "${{ matrix.test_group.test_type }}" == "sh" ]; then
158+ echo "::group::Executing Legacy Shell Script"
159+ # Dynamically detect TE installation path to avoid "SO not found" errors
160+ export TE_LIB_PATH=$(python3 -c "import transformer_engine; import os; print(os.path.dirname(transformer_engine.__file__))")
161+
162+ # Special env for Lint group
163+ if [[ "${{ matrix.test_group.name }}" == *"lint"* ]]; then
164+ export CPP_ONLY=0
165+ export PYTHON_ONLY=0
268166 fi
167+ bash ${{ matrix.test_group.path }}
168+ echo "::endgroup::"
169+ else
170+ echo "::group::Executing Modern Pytest"
171+ # Build deselect options from ignored_tests input
172+ IGNORED_TESTS='${{ inputs.ignored_tests }}'
173+ IGNORE_OPTS=$(echo "$IGNORED_TESTS" | python3 -c "import sys, json; t = json.load(sys.stdin); print(' '.join(['--deselect=' + i for i in t])) if t else print('')")
174+
175+ # Run distributed tests with torchrun
176+ torchrun --nproc_per_node=$NUM_GPUS -m pytest -v ${{ matrix.test_group.path }} $IGNORE_OPTS -p no:randomly
177+ echo "::endgroup::"
269178 fi
270-
271- # Run unit tests with torchrun
272- # Each test group runs in isolation to avoid state pollution
273- NUM_GPUS=$(python3 -c "import torch; print(torch.cuda.device_count())")
274- echo "=== Detected $NUM_GPUS GPUs, starting torchrun ==="
275-
276- # 使用动态获取的数量启动测试
277- torchrun --nproc_per_node=$NUM_GPUS -m pytest -v $TEST_PATH $IGNORE_OPTS -p no:randomly
278-
279- exit_code=$?
280- echo "exit_code=$exit_code" >> $GITHUB_OUTPUT
281- exit $exit_code
282- timeout-minutes : 60
179+ timeout-minutes : 60
0 commit comments