Skip to content

Commit 562537a

Browse files
authored
chore: experimental parallel kokoro system test (#17608)
> [!note] > - This is intended to test parallelization of system tests in CI/CD. > - It is paired with a non-parallelized version to benchmark any improvement. #17645 ### Results Baseline: [2 hours 5 mins](https://btx.cloud.google.com/invocations/34ed19da-da1a-4cae-bc1b-a1f52ca20927/targets) With parallelization: [42 mins](https://btx.cloud.google.com/invocations/c0b4abe6-806b-4818-87b0-6b1574c075e7/targets) This was blocked on: #17826
1 parent 4de32a5 commit 562537a

3 files changed

Lines changed: 145 additions & 10 deletions

File tree

.kokoro/system.sh

Lines changed: 144 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,39 @@ RETVAL=0
3535

3636
pwd
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+
3852
run_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
101191
system_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
104196
for 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
155247
done
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+
156293
exit ${RETVAL}

packages/google-auth/setup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
import io
1616
import os
1717

18-
from setuptools import find_namespace_packages
19-
from setuptools import setup
18+
from setuptools import find_namespace_packages, setup
2019

2120
cryptography_base_require = [
2221
"cryptography >= 38.0.3; python_version < '3.14'",

packages/google-cloud-core/setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import setuptools
1919

20-
2120
# Package metadata.
2221

2322
name = "google-cloud-core"

0 commit comments

Comments
 (0)