Fix node-facts.sh bugs and add stub-curl integration tests

- Fix grep -qE calls to handle variables starting with '-' (add -- separator)
- Remove local declarations at top level by wrapping main body in main() function
- Replace bounded-worker scheduler with simpler temp file + wait -n pattern
- Fix per-node fan-out to capture function output instead of re-calling
- Add stub-curl integration tests that catch all three original issues
- Add fixture compose files for avalanche, op-node+beacon, geth testing
- Update test path-blacklist.txt to include entry starting with -

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-10-06 07:22:51 +00:00
parent d57d19276e
commit fe22be322e
7 changed files with 367 additions and 83 deletions
+75 -83
View File
@@ -71,7 +71,7 @@ fi
should_include() {
local path="$1"
for word in "${blacklist[@]}"; do
if echo "$path" | grep -qE "$word"; then
if echo "$path" | grep -qE -- "$word"; then
return 1
fi
done
@@ -86,7 +86,7 @@ get_node_compose_files() {
# Remove leading ./ and trailing .yml if present
part="$(echo "$part" | sed 's|^\./||; s|\.yml$||')"
# Only include if it's a real compose file (contains hyphens, not base/rpc/etc)
if echo "$part" | grep -q "-" && should_include "$part"; then
if echo "$part" | grep -q -- "-" && should_include "$part"; then
echo "$part"
fi
done
@@ -133,7 +133,7 @@ get_client_info() {
if [ -n "$services" ]; then
# Try to find image for this service
local image_line=$(grep -A 20 "^\s+${services}:" "$compose_file" | grep -oP 'image:\s*\K[^\s]+' | head -1)
local image_line=$(grep -A 20 -- "^\s+${services}:" "$compose_file" | grep -oP -- 'image:\s*\K[^\s]+' | head -1)
if [ -n "$image_line" ]; then
# Parse image:tag
client_image="$(echo "$image_line" | cut -d':' -f1)"
@@ -698,52 +698,51 @@ get_node_facts() {
echo "${sig_result}|${elapsed}"
}
# Run all data collection functions in parallel
# Run all data collection functions in parallel and capture output
local version_pid
local peers_pid
local schedule_pid
local head_pid
local signals_pid
local version_result
local peers_result
local schedule_result
local head_result
local signals_result
get_version &
version_result=$(get_version) &
version_pid=$!
get_peers &
peers_result=$(get_peers) &
peers_pid=$!
get_schedule &
schedule_result=$(get_schedule) &
schedule_pid=$!
get_head &
head_result=$(get_head) &
head_pid=$!
get_signals &
signals_result=$(get_signals) &
signals_pid=$!
# Wait for all to complete
local results=()
for pid in $version_pid $peers_pid $schedule_pid $head_pid $signals_pid; do
wait "$pid"
done
# Collect results
version_result=$(get_version)
# Collect results from captured output
version_json=$(echo "$version_result" | cut -d'|' -f1)
version_time=$(echo "$version_result" | cut -d'|' -f2)
peers_result=$(get_peers)
peers_json=$(echo "$peers_result" | cut -d'|' -f1)
peers_time=$(echo "$peers_result" | cut -d'|' -f2)
schedule_result=$(get_schedule)
schedule_json=$(echo "$schedule_result" | cut -d'|' -f1)
schedule_time=$(echo "$schedule_result" | cut -d'|' -f2)
head_result=$(get_head)
head_json=$(echo "$head_result" | cut -d'|' -f1)
head_time=$(echo "$head_result" | cut -d'|' -f2)
signals_result=$(get_signals)
signals_json=$(echo "$signals_result" | cut -d'|' -f1)
signals_time=$(echo "$signals_result" | cut -d'|' -f2)
@@ -829,76 +828,69 @@ get_node_facts() {
echo "$doc"
}
# Main execution
if [ -n "$node_path" ]; then
# Single node mode
if should_include "$node_path"; then
get_node_facts "$node_path" "$PRETTY"
# Main execution function
main() {
if [ -n "$node_path" ]; then
# Single node mode
if should_include "$node_path"; then
get_node_facts "$node_path" "$PRETTY"
else
echo "error: node_path '$node_path' is blacklisted" >&2
exit 1
fi
else
echo "error: node_path '$node_path' is blacklisted" >&2
exit 1
fi
else
# All nodes mode - iterate over all node compose files
local node_files=()
while IFS= read -r node_file; do
[ -z "$node_file" ] && continue
node_files+=("$node_file")
done < <(get_node_compose_files)
# Parallel execution with bounded workers
local max_workers=${MAX_WORKERS:-8}
local pids=()
local results=()
local current_workers=0
local index=0
for node_file in "${node_files[@]}"; do
# Wait if we have too many workers
while [ $current_workers -ge $max_workers ]; do
for i in "${!pids[@]}"; do
if ! kill -0 "${pids[$i]}" 2>/dev/null; then
# Process completed
local result=$(wait "${pids[$i]}" 2>/dev/null && echo "" || echo "")
results+=("$result")
unset pids[$i]
pids=("${pids[@]}")
current_workers=$((current_workers - 1))
break
fi
done
# If still at max, sleep briefly
if [ $current_workers -ge $max_workers ]; then
sleep 0.1
# All nodes mode - iterate over all node compose files
node_files=()
while IFS= read -r node_file; do
[ -z "$node_file" ] && continue
node_files+=("$node_file")
done < <(get_node_compose_files)
# Create temp directory for output files
temp_dir=$(mktemp -d)
# Track pids and temp files
pids=()
temp_files=()
max_workers=${MAX_WORKERS:-8}
for node_file in "${node_files[@]}"; do
temp_file="$temp_dir/$(basename "$node_file" .yml).json"
( get_node_facts "$node_file" "$PRETTY" > "$temp_file" ) &
pids+=($!)
temp_files+=("$temp_file")
# Wait if we reached max workers
if [ ${#pids[@]} -ge $max_workers ]; then
wait -n
# Remove the completed pid and corresponding temp file
completed_pid="$?"
for i in "${!pids[@]}"; do
if [ "${pids[$i]}" = "$completed_pid" ]; then
unset pids[$i]
unset temp_files[$i]
break
fi
done
pids=("${pids[@]}")
temp_files=("${temp_files[@]}")
fi
done
# Start new worker
{
local result=$(get_node_facts "$node_file" "$PRETTY")
echo "${result}"
} &
pids+=($!)
current_workers=$((current_workers + 1))
index=$((index + 1))
done
# Wait for remaining workers
for pid in "${pids[@]}"; do
wait "$pid" 2>/dev/null
done
# Since we're outputting JSON lines, we already printed results in the workers
# But to maintain order, let's do a simpler sequential approach for JSON lines
# Actually, let's redo this properly for streaming JSON lines
# Clear the partial parallel results and do sequential for JSON lines
echo "" # Separator
# Sequential approach for JSON lines (to maintain order)
for node_file in "${node_files[@]}"; do
get_node_facts "$node_file" "$PRETTY"
done
fi
# Wait for all remaining workers
wait
# Output results in order
for temp_file in "${temp_files[@]}"; do
cat "$temp_file"
done
# Clean up temp directory
rm -rf "$temp_dir"
fi
}
# Call main function
main
exit 0