@@ -35,17 +35,39 @@ RETVAL=0
3535
3636pwd
3737
38+ echo " === KOKORO VM SCOUTING ==="
39+ echo " CPU Count:"
40+ nproc
41+ echo " --------------------------"
42+ echo " Detailed CPU Info:"
43+ lscpu | grep -E " ^(Model name|CPU\(s\)|Thread\(s\) per core|Core\(s\) per socket)"
44+ echo " --------------------------"
45+ echo " Memory Status:"
46+ free -h
47+ echo " --------------------------"
48+ echo " Disk Usage:"
49+ df -h /
50+ echo " =========================="
51+
3852run_package_test () {
3953 local package_name=$1
4054 local package_path=" packages/${package_name} "
41-
55+
4256 # Declare local overrides to prevent bleeding into the next loop iteration
4357 local PROJECT_ID
4458 local GOOGLE_APPLICATION_CREDENTIALS
4559 local NOX_FILE
4660 # Inherit NOX_SESSION from environment to allow configs (like prerelease.cfg) to pass it in
4761 local NOX_SESSION=" ${NOX_SESSION} "
4862
63+ # ISOLATION: Create a unique gcloud config dir for this run
64+ local gcloud_config_dir=$( mktemp -d -t " gcloud-config-${package_name} -XXXXXX" )
65+ local CLOUDSDK_CONFIG=" ${gcloud_config_dir} "
66+
67+ # 🪤 TRAP: Ensure cleanup of THIS specific temp dir on exit of this subshell
68+ trap ' rm -rf "$gcloud_config_dir"' EXIT
69+
70+
4971 echo " ------------------------------------------------------------"
5072 echo " Configuring environment for: ${package_name} "
5173 echo " ------------------------------------------------------------"
@@ -80,11 +102,13 @@ run_package_test() {
80102 esac
81103
82104 # Export variables for the duration of this function's sub-processes
83- export PROJECT_ID GOOGLE_APPLICATION_CREDENTIALS NOX_FILE NOX_SESSION
105+ export PROJECT_ID GOOGLE_APPLICATION_CREDENTIALS NOX_FILE NOX_SESSION CLOUDSDK_CONFIG
84106 export GOOGLE_CLOUD_PROJECT=" ${PROJECT_ID} "
85107
86- gcloud auth activate-service-account --key-file=" $GOOGLE_APPLICATION_CREDENTIALS "
87- gcloud config set project " $PROJECT_ID "
108+ # 🛡️ Explicit check: Fail early if auth fails
109+ gcloud auth activate-service-account --key-file=" $GOOGLE_APPLICATION_CREDENTIALS " || return 1
110+ export CLOUDSDK_CORE_PROJECT=" ${PROJECT_ID} "
111+
88112
89113 # Run the actual test
90114 pushd " ${package_path} " > /dev/null
@@ -93,13 +117,81 @@ run_package_test() {
93117 local res=$?
94118 set -e
95119 popd > /dev/null
96-
120+
97121 return $res
98122}
99123
124+ # Analyzes results of parallel test runs, prints summary, and dumps failed logs
125+ reap_parallel_results () {
126+ local retval=0
127+ local failed_count=0
128+ local passed_count=0
129+
130+ if [ -z " $LOG_DIR " ]; then
131+ echo " Error: LOG_DIR is not set."
132+ return 1
133+ fi
134+
135+ # Count failed packages by checking for .failed marker files
136+ for failed in " $LOG_DIR " /* .failed; do
137+ if [ -f " $failed " ]; then
138+ failed_count=$(( failed_count + 1 ))
139+ fi
140+ done
141+
142+ local total_tested=${# PACKAGES_TO_TEST[@]}
143+ passed_count=$(( total_tested - failed_count))
144+
145+ echo " "
146+ echo " =================================================="
147+ echo " TEST RUN SUMMARY "
148+ echo " =================================================="
149+ echo " Total tested: $total_tested "
150+ echo " Passed: $passed_count "
151+ echo " Failed: $failed_count "
152+ echo " =================================================="
153+
154+ local passed_packages=()
155+ for pkg in " ${PACKAGES_TO_TEST[@]} " ; do
156+ if [ ! -f " $LOG_DIR /$pkg .failed" ]; then
157+ passed_packages+=(" $pkg " )
158+ fi
159+ done
160+
161+ if [ ${# passed_packages[@]} -gt 0 ]; then
162+ echo " "
163+ echo " PASSED PACKAGES:"
164+ printf " %s\n" " ${passed_packages[@]} " | sort | sed ' s/^/- /'
165+ fi
166+
167+ if [ " $failed_count " -gt 0 ]; then
168+ echo " "
169+ echo " !!! DETAILED LOGS FOR FAILED PACKAGES !!!"
170+ for failed in " $LOG_DIR " /* .failed; do
171+ if [ -f " $failed " ]; then
172+ local pkg=$( basename " $failed " .failed)
173+ echo " --------------------------------------------------"
174+ echo " LOGS FOR: $pkg "
175+ echo " --------------------------------------------------"
176+ if [ -n " $KOKORO_ARTIFACTS_DIR " ] && [ -f " $KOKORO_ARTIFACTS_DIR /$pkg /sponge_log.log" ]; then
177+ cat " $KOKORO_ARTIFACTS_DIR /$pkg /sponge_log.log"
178+ else
179+ cat " $LOG_DIR /$pkg .log"
180+ fi
181+ echo " "
182+ fi
183+ done
184+ retval=1
185+ fi
186+ return $retval
187+ }
188+
189+
100190# A file for running system tests
101191system_test_script=" ${PROJECT_ROOT} /.kokoro/system-single.sh"
102192
193+ PACKAGES_TO_TEST=()
194+
103195# Run system tests for each package with directory packages/*/tests/system
104196for path in ` find ' packages' \
105197 \( -type d -wholename ' packages/*/tests/system' \) -o \
@@ -113,6 +205,7 @@ for path in `find 'packages' \
113205 package_name=${package_name%%/* }
114206 package_path=" packages/${package_name} "
115207
208+
116209 # Determine if we should skip based on git diff
117210 # We always check for changes in these specific versioning/config files
118211 files_to_check=(
@@ -147,10 +240,54 @@ for path in `find 'packages' \
147240 set -e
148241
149242 if [[ " ${package_modified} " -gt 0 || " $KOKORO_BUILD_ARTIFACTS_SUBDIR " == * " continuous" * ]]; then
150- # Call the function - its internal exports won't affect the next loop
151- run_package_test " $package_name " || RETVAL=$?
243+ PACKAGES_TO_TEST+=(" $package_name " )
152244 else
153245 echo " No changes in ${package_name} and not a continuous build, skipping."
154246 fi
155247done
248+
249+ # Parallel Execution Logic
250+ MAX_JOBS=${MAX_JOBS:- 4}
251+
252+ # Temporary directory for clean log segregation
253+ LOG_DIR=$( mktemp -d -t test-logs-XXXXXX)
254+ # Clean up logs on exit
255+ trap ' rm -rf "$LOG_DIR"' EXIT
256+
257+ if [ ${# PACKAGES_TO_TEST[@]} -eq 0 ]; then
258+ echo " No packages to test."
259+ exit 0
260+ fi
261+
262+ echo " =================================================="
263+ echo " Starting parallel test execution for ${# PACKAGES_TO_TEST[@]} packages"
264+ echo " Concurrency limit: ${MAX_JOBS} "
265+ echo " =================================================="
266+
267+ export LOG_DIR
268+ export -f run_package_test
269+ export system_test_script PROJECT_ROOT KOKORO_GFILE_DIR
270+
271+ # Stream package names to xargs for parallel execution
272+ # -P "$MAX_JOBS" controls concurrency
273+ # -I {} replaces {} with the package name
274+ printf ' %s\n' " ${PACKAGES_TO_TEST[@]} " \
275+ | xargs -P " $MAX_JOBS " -I {} \
276+ bash -c '
277+ pkg="$1"
278+ # Determine log location: prefer Sponge artifacts directory if available
279+ if [ -n "$KOKORO_ARTIFACTS_DIR" ]; then
280+ pkg_log_dir="$KOKORO_ARTIFACTS_DIR/$pkg"
281+ mkdir -p "$pkg_log_dir" || { touch "$LOG_DIR/$pkg.failed"; exit 1; }
282+ log_file="$pkg_log_dir/sponge_log.log"
283+ else
284+ log_file="$LOG_DIR/$pkg.log"
285+ fi
286+
287+ # Run test; if it fails, create a .failed file to signal failure to the reaper
288+ run_package_test "$pkg" > "$log_file" 2>&1 || touch "$LOG_DIR/$pkg.failed"
289+ ' _ " {}"
290+
291+ reap_parallel_results || RETVAL=1
292+
156293exit ${RETVAL}
0 commit comments