Skip to content

Commit edb4451

Browse files
Bordalexierule
authored andcommitted
ci: resolve standalone testing (#20633)
* ci: resolve standalone testing * faster * merge * printenv * here * list * prune * process * printf * stdout * ./ * -e * .coverage * all * rev * notes * notes * notes (cherry picked from commit e8d70bc)
1 parent 6cb697f commit edb4451

File tree

6 files changed

+79
-33
lines changed

6 files changed

+79
-33
lines changed

.azure/gpu-benchmarks.yml

+1
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,6 @@ jobs:
108108
condition: and(succeeded(), eq(variables['PACKAGE_NAME'], 'fabric'))
109109
env:
110110
PL_RUN_CUDA_TESTS: "1"
111+
PL_RUN_STANDALONE_TESTS: "1"
111112
displayName: "Testing: fabric standalone tasks"
112113
timeoutInMinutes: "10"

.azure/gpu-tests-fabric.yml

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ jobs:
144144
workingDirectory: tests/
145145
env:
146146
PL_STANDALONE_TESTS_SOURCE: $(COVERAGE_SOURCE)
147+
PL_RUN_STANDALONE_TESTS: "1"
147148
displayName: "Testing: fabric standalone"
148149
timeoutInMinutes: "10"
149150

.azure/gpu-tests-pytorch.yml

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ jobs:
166166
env:
167167
PL_USE_MOCKED_MNIST: "1"
168168
PL_STANDALONE_TESTS_SOURCE: $(COVERAGE_SOURCE)
169+
PL_RUN_STANDALONE_TESTS: "1"
169170
displayName: "Testing: PyTorch standalone tests"
170171
timeoutInMinutes: "35"
171172

tests/run_standalone_tests.sh

+68-33
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,61 @@
1212
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
15-
set -e
16-
# THIS FILE ASSUMES IT IS RUN INSIDE THE tests/tests_<package> DIRECTORY
15+
16+
# THIS FILE ASSUMES IT IS RUN INSIDE THE tests DIRECTORY.
1717

1818
# Batch size for testing: Determines how many standalone test invocations run in parallel
19-
# It can be set through the env variable PL_STANDALONE_TESTS_BATCH_SIZE and defaults to 6 if not set
20-
test_batch_size="${PL_STANDALONE_TESTS_BATCH_SIZE:-3}"
21-
source="${PL_STANDALONE_TESTS_SOURCE:-"lightning"}"
22-
# this is the directory where the tests are located
19+
# It can be set through the env variable NUM_PARALLEL_TESTS and defaults to 5 if not set
20+
test_batch_size="${NUM_PARALLEL_TESTS:-5}"
21+
22+
# Source directory for coverage runs can be set with CODECOV_SOURCE and defaults to lightning.
23+
codecov_source="${CODECOV_SOURCE:-"lightning"}"
24+
25+
# The test directory is passed as the first argument to the script
2326
test_dir=$1 # parse the first argument
27+
28+
# There is also timeout for the tests.
29+
# It can be set through the env variable TEST_TIMEOUT and defaults to 1200 seconds if not set 1200 seconds
30+
test_timeout="${TEST_TIMEOUT:-1200}"
31+
32+
# Temporary file to store the collected tests
2433
COLLECTED_TESTS_FILE="collected_tests.txt"
2534

2635
ls -lh . # show the contents of the directory
2736

28-
# this environment variable allows special tests to run
29-
export PL_RUN_STANDALONE_TESTS=1
30-
# python arguments
31-
defaults=" -m coverage run --source ${source} --append -m pytest --no-header -v -s --timeout 120 "
37+
# Python arguments for running the tests and coverage
38+
defaults=" -m coverage run --source ${codecov_source} --append -m pytest --no-header -v -s --color=yes --timeout=${test_timeout} --durations=0 "
3239
echo "Using defaults: ${defaults}"
3340

34-
# get the list of parametrizations. we need to call them separately. the last two lines are removed.
41+
# Get the list of parametrizations. we need to call them separately. the last two lines are removed.
3542
# note: if there's a syntax error, this will fail with some garbled output
36-
python3 -um pytest $test_dir -q --collect-only --pythonwarnings ignore 2>&1 > $COLLECTED_TESTS_FILE
37-
# early terminate if collection failed (e.g. syntax error)
43+
python -um pytest ${test_dir} -q --collect-only --pythonwarnings ignore 2>&1 > $COLLECTED_TESTS_FILE
44+
# Early terminate if collection failed (e.g. syntax error)
3845
if [[ $? != 0 ]]; then
3946
cat $COLLECTED_TESTS_FILE
47+
printf "ERROR: test collection failed!\n"
4048
exit 1
4149
fi
4250

43-
# removes the last line of the file
44-
sed -i '$d' $COLLECTED_TESTS_FILE
51+
# Initialize empty array
52+
tests=()
4553

46-
# Get test list and run each test individually
47-
tests=($(grep -oP '\S+::test_\S+' "$COLLECTED_TESTS_FILE"))
54+
# Read from file line by line
55+
while IFS= read -r line; do
56+
# Only keep lines containing "test_"
57+
if [[ $line == *"test_"* ]]; then
58+
# Extract part after test_dir/
59+
pruned_line="${line#*${test_dir}/}"
60+
tests+=("${test_dir}/$pruned_line")
61+
fi
62+
done < $COLLECTED_TESTS_FILE
63+
64+
# Count tests
4865
test_count=${#tests[@]}
49-
# present the collected tests
66+
67+
# Display results
5068
printf "collected $test_count tests:\n-------------------\n"
51-
# replace space with new line
52-
echo "${tests[@]}" | tr ' ' '\n'
69+
printf "%s\n" "${tests[@]}"
5370
printf "\n===================\n"
5471

5572
# if test count is one print warning
@@ -63,55 +80,73 @@ fi
6380
# clear all the collected reports
6481
rm -f parallel_test_output-*.txt # in case it exists, remove it
6582

66-
67-
status=0 # reset the script status
83+
status=0 # aggregated script status
6884
report="" # final report
6985
pids=() # array of PID for running tests
7086
test_ids=() # array of indexes of running tests
71-
printf "Running $test_count tests in batches of $test_batch_size\n"
87+
failed_tests=() # array of failed tests
88+
printf "Running $test_count tests in batches of $test_batch_size:\n"
7289
for i in "${!tests[@]}"; do
73-
# remove initial "tests/" from the test name
74-
test=${tests[$i]/tests\//}
75-
printf "Running test $((i+1))/$test_count: $test\n"
90+
test=${tests[$i]}
91+
printf "* Running test $((i+1))/$test_count: $test\n"
7692

7793
# execute the test in the background
7894
# redirect to a log file that buffers test output. since the tests will run in the background,
7995
# we cannot let them output to std{out,err} because the outputs would be garbled together
80-
python3 ${defaults} "$test" 2>&1 > "standalone_test_output-$i.txt" &
96+
python ${defaults} "$test" &> "parallel_test_output-$i.txt" &
8197
test_ids+=($i) # save the test's id in an array with running tests
8298
pids+=($!) # save the PID in an array with running tests
8399

84100
# if we reached the batch size, wait for all tests to finish
85101
if (( (($i + 1) % $test_batch_size == 0) || $i == $test_count-1 )); then
86-
printf "Waiting for batch to finish: $(IFS=' '; echo "${pids[@]}")\n"
102+
printf "-> Waiting for batch to finish: $(IFS=' '; echo "${pids[@]}")\n"
87103
# wait for running tests
88104
for j in "${!test_ids[@]}"; do
89105
i=${test_ids[$j]} # restore the global test's id
90106
pid=${pids[$j]} # restore the particular PID
91107
test=${tests[$i]} # restore the test name
92-
printf "Waiting for $tests >> standalone_test_output-$i.txt (PID: $pid)\n"
108+
printf "? Waiting for $tests >> parallel_test_output-$i.txt (PID: $pid)\n"
93109
wait -n $pid
94110
# get the exit status of the test
95111
test_status=$?
96112
# add row to the final report
97113
report+="Ran\t$test\t>> exit:$test_status\n"
98114
if [[ $test_status != 0 ]]; then
99-
# show the output of the failed test
100-
cat "standalone_test_output-$i.txt"
115+
# add the test to the failed tests array
116+
failed_tests+=($i)
101117
# Process exited with a non-zero exit status
102118
status=$test_status
103119
fi
104120
done
121+
printf "Starting over with a new batch...\n"
105122
test_ids=() # reset the test's id array
106123
pids=() # reset the PID array
107124
fi
108125
done
109126

110-
# echo test report
127+
# print test report with exit code for each test
111128
printf '=%.s' {1..80}
112129
printf "\n$report"
113130
printf '=%.s' {1..80}
114131
printf '\n'
115132

116-
# exit with the worst test result
133+
# print failed tests from duped logs
134+
if [[ ${#failed_tests[@]} -gt 0 ]]; then
135+
printf "Failed tests:\n"
136+
for i in "${failed_tests[@]}"; do
137+
printf '\n%.s' {1..5}
138+
printf '=%.s' {1..80}
139+
printf "\n${tests[$i]}\n"
140+
printf '-%.s' {1..80}
141+
printf "\n"
142+
# show the output of the failed test
143+
cat "parallel_test_output-$i.txt"
144+
printf "\n"
145+
printf '=%.s' {1..80}
146+
done
147+
else
148+
printf "All tests passed!\n"
149+
fi
150+
151+
# exit with the worse test result
117152
exit $status

tests/tests_fabric/conftest.py

+4
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,16 @@ def caplog(caplog):
191191

192192
@pytest.fixture(autouse=True)
193193
def leave_no_artifacts_behind():
194+
"""Checks that no artifacts are left behind after the test."""
194195
tests_root = Path(__file__).parent.parent
196+
# Ignore the __pycache__ directories
195197
files_before = {p for p in tests_root.rglob("*") if "__pycache__" not in p.parts}
196198
yield
197199
files_after = {p for p in tests_root.rglob("*") if "__pycache__" not in p.parts}
198200
difference = files_after - files_before
199201
difference = {str(f.relative_to(tests_root)) for f in difference}
202+
# ignore the .coverage files
203+
difference = {f for f in difference if not f.endswith(".coverage")}
200204
assert not difference, f"Test left artifacts behind: {difference}"
201205

202206

tests/tests_pytorch/conftest.py

+4
Original file line numberDiff line numberDiff line change
@@ -312,12 +312,16 @@ def single_process_pg():
312312

313313
@pytest.fixture(autouse=True)
314314
def leave_no_artifacts_behind():
315+
"""Checks that no artifacts are left behind after the test."""
315316
tests_root = Path(__file__).parent.parent
317+
# Ignore the __pycache__ directories
316318
files_before = {p for p in tests_root.rglob("*") if "__pycache__" not in p.parts}
317319
yield
318320
files_after = {p for p in tests_root.rglob("*") if "__pycache__" not in p.parts}
319321
difference = files_after - files_before
320322
difference = {str(f.relative_to(tests_root)) for f in difference}
323+
# ignore the .coverage files
324+
difference = {f for f in difference if not f.endswith(".coverage")}
321325
assert not difference, f"Test left artifacts behind: {difference}"
322326

323327

0 commit comments

Comments
 (0)