From 703a6ebc35aa778775615a38a76a05ff3cf861f7 Mon Sep 17 00:00:00 2001 From: Teja Swaroop Moida Date: Fri, 19 Sep 2025 10:55:56 +0530 Subject: [PATCH] Add Network Bring-Up and Fix SKIP Handling - Added generic network bring-up with interface checks. - Centralized audio asset fetching logic. - Updated playback script to SKIP when offline and corrected the final status. Signed-off-by: Teja Swaroop Moida --- .../Multimedia/Audio/AudioPlayback/Read_me.md | 31 ++- .../Multimedia/Audio/AudioPlayback/run.sh | 18 +- .../Multimedia/Audio/AudioRecord/Read_me.md | 8 + Runner/utils/audio_common.sh | 66 +++++- Runner/utils/functestlib.sh | 188 ++++++++++++++++++ 5 files changed, 296 insertions(+), 15 deletions(-) diff --git a/Runner/suites/Multimedia/Audio/AudioPlayback/Read_me.md b/Runner/suites/Multimedia/Audio/AudioPlayback/Read_me.md index 2a9701d8..a095d948 100644 --- a/Runner/suites/Multimedia/Audio/AudioPlayback/Read_me.md +++ b/Runner/suites/Multimedia/Audio/AudioPlayback/Read_me.md @@ -7,7 +7,6 @@ This suite automates the validation of audio playback capabilities on Qualcomm L ## Features - - Supports **PipeWire** and **PulseAudio** backends - Plays audio clips with configurable format, duration, and loop count - Automatically downloads and extracts audio assets if missing @@ -63,22 +62,45 @@ ssh user@target_device_ip **Using Unified Runner** cd /Runner + # Run AudioPlayback using PipeWire (auto-detects backend if not specified) ./run-test.sh AudioPlayback + # Force PulseAudio backend AUDIO_BACKEND=pulseaudio ./run-test.sh AudioPlayback + # Custom options via environment variables AUDIO_BACKEND=pipewire PLAYBACK_TIMEOUT=20s PLAYBACK_LOOPS=2 ./run-test.sh AudioPlayback +# Disable asset extraction (offline mode) +EXTRACT_AUDIO_ASSETS=false ./run-test.sh AudioPlayback + +# Provide Wi-Fi credentials for asset download +SSID="MyNetwork" PASSWORD="MyPassword" ./run-test.sh AudioPlayback + +# Override network probe targets (useful in restricted networks) +NET_PROBE_ROUTE_IP=192.168.1.1 NET_PING_HOST=192.168.1.254 ./run-test.sh AudioPlayback + + **Directly from Test Directory** cd Runner/suites/Multimedia/Audio/AudioPlayback # Show usage/help ./run.sh --help + # Run with PipeWire, 3 loops, 10s timeout, speakers sink ./run.sh --backend pipewire --sink speakers --loops 3 --timeout 10s + # Run with PulseAudio, null sink, strict mode, verbose ./run.sh --backend pulseaudio --sink null --strict --verbose +# Disable asset extraction (offline mode) +./run.sh --no-extract-assets + +# Provide JUnit output and disable dmesg scan +./run.sh --junit results.xml --no-dmesg + + + Environment Variables: Variable Description Default AUDIO_BACKEND Selects backend: pipewire or pulseaudio auto-detect @@ -92,6 +114,11 @@ DMESG_SCAN Scan dmesg for errors after playback 1 VERBOSE Enable verbose logging 0 EXTRACT_AUDIO_ASSETS Download/extract audio assets if missing true JUNIT_OUT Path to write JUnit XML output unset +SSID Wi-Fi SSID for network connection unset +PASSWORD Wi-Fi password for network connection unset +NET_PROBE_ROUTE_IP IP used for route probing (default: 1.1.1.1) 1.1.1.1 +NET_PING_HOST Host used for ping reachability check 8.8.8.8 + CLI Options Option Description @@ -142,6 +169,8 @@ Diagnostic logs: dmesg snapshots, mixer dumps, playback logs per test case - If any critical tool is missing, the script exits with an error message. - Logs include dmesg snapshots, mixer dumps, and playback logs. - Asset download requires network connectivity. +- Pass Wi-Fi credentials via SSID and PASSWORD environment variables to enable network access for asset downloads and playback validation. +- You can override default network probe targets using NET_PROBE_ROUTE_IP and NET_PING_HOST to avoid connectivity-related failures in restricted environments. - Evidence-based PASS/FAIL logic ensures reliability even if backend quirks occur. ## License diff --git a/Runner/suites/Multimedia/Audio/AudioPlayback/run.sh b/Runner/suites/Multimedia/Audio/AudioPlayback/run.sh index c684c6f8..32b15d86 100755 --- a/Runner/suites/Multimedia/Audio/AudioPlayback/run.sh +++ b/Runner/suites/Multimedia/Audio/AudioPlayback/run.sh @@ -175,11 +175,15 @@ for fmt in $FORMATS; do fi if [ "${EXTRACT_AUDIO_ASSETS:-true}" = "true" ]; then - ensure_playback_clip "$clip" || { - log_warn "[$case_name] Clip missing and could not be fetched: $clip" - echo "$case_name SKIP (clip missing)" >> "$LOGDIR/summary.txt" - append_junit "$case_name" "0" "SKIP" "$logf"; skip=$((skip + 1)); continue - } + audio_ensure_clip_ready "$clip" "$AUDIO_TAR_URL" + rc=$? + if [ "$rc" -eq 2 ] || [ "$rc" -eq 1 ]; then + log_skip "[$case_name] SKIP: Required clip missing and network unavailable or fetch failed." + echo "$case_name SKIP (clip missing)" >> "$LOGDIR/summary.txt" + append_junit "$case_name" "0" "SKIP" "$logf" + skip=$((skip + 1)) + continue + fi fi i=1; ok_runs=0; last_elapsed=0 @@ -274,7 +278,9 @@ if [ -n "$JUNIT_OUT" ]; then log_info "Wrote JUnit: $JUNIT_OUT" fi -if [ "$suite_rc" -eq 0 ]; then +if [ "$pass" -eq 0 ] && [ "$fail" -eq 0 ] && [ "$skip" -gt 0 ]; then + log_skip "$TESTNAME SKIP"; echo "$TESTNAME SKIP" > "$RES_FILE" +elif [ "$suite_rc" -eq 0 ]; then log_pass "$TESTNAME PASS"; echo "$TESTNAME PASS" > "$RES_FILE" else log_fail "$TESTNAME FAIL"; echo "$TESTNAME FAIL" > "$RES_FILE" diff --git a/Runner/suites/Multimedia/Audio/AudioRecord/Read_me.md b/Runner/suites/Multimedia/Audio/AudioRecord/Read_me.md index 7e6a657d..70cc9c32 100644 --- a/Runner/suites/Multimedia/Audio/AudioRecord/Read_me.md +++ b/Runner/suites/Multimedia/Audio/AudioRecord/Read_me.md @@ -63,19 +63,26 @@ ssh user@target_device_ip **Using Unified Runner** cd Runner + # Run Audiorecord using PipeWire (auto-detects backend if not specified) ./run-test.sh Audiorecord + # Force PulseAudio backend AUDIO_BACKEND=pulseaudio ./run-test.sh Audiorecord + # Custom options via environment variables AUDIO_BACKEND=pipewire RECORD_TIMEOUT=20s RECORD_LOOPS=2 RECORD_VOLUME=0.5 ./run-test.sh Audiorecord + **Directly from Test Directory** cd Runner/suites/Multimedia/Audio/Audiorecord + # Show usage/help ./run.sh --help + # Run with PipeWire, 3 loops, 10s timeout, mic source ./run.sh --backend pipewire --source mic --loops 3 --timeout 10s + # Run with PulseAudio, null source, strict mode, verbose ./run.sh --backend pulseaudio --source null --strict --verbose @@ -93,6 +100,7 @@ DMESG_SCAN Scan dmesg for errors after recording 1 VERBOSE Enable verbose logging 0 JUNIT_OUT Path to write JUnit XML output unset + CLI Options: Option Description --backend Select backend: pipewire or pulseaudio diff --git a/Runner/utils/audio_common.sh b/Runner/utils/audio_common.sh index 815f0d6c..9393cac0 100755 --- a/Runner/utils/audio_common.sh +++ b/Runner/utils/audio_common.sh @@ -37,14 +37,64 @@ resolve_clip() { esac } -ensure_playback_clip() { - clip="$1" - [ -f "$clip" ] && return 0 - if [ -n "$AUDIO_TAR_URL" ]; then - log_info "Audio clip missing, extracting from $AUDIO_TAR_URL" - extract_tar_from_url "$AUDIO_TAR_URL" || return 1 - fi - [ -f "$clip" ] +# audio_download_with_any +audio_download_with_any() { + url="$1"; out="$2" + if command -v wget >/dev/null 2>&1; then + wget -O "$out" "$url" + elif command -v curl >/dev/null 2>&1; then + curl -L --fail -o "$out" "$url" + else + log_error "No downloader (wget/curl) available to fetch $url" + return 1 + fi +} +# audio_fetch_assets_from_url +# Prefer functestlib's extract_tar_from_url; otherwise download + extract. +audio_fetch_assets_from_url() { + url="$1" + if command -v extract_tar_from_url >/dev/null 2>&1; then + extract_tar_from_url "$url" + return $? + fi + fname="$(basename "$url")" + log_info "Fetching assets: $url" + if ! audio_download_with_any "$url" "$fname"; then + log_warn "Download failed: $url" + return 1 + fi + tar -xzf "$fname" >/dev/null 2>&1 || tar -xf "$fname" >/dev/null 2>&1 || { + log_warn "Extraction failed: $fname" + return 1 + } + return 0 +} +# audio_ensure_clip_ready [tarball-url] +# Return codes: +# 0 = clip exists/ready +# 2 = network unavailable after attempts (caller should SKIP) +# 1 = fetch/extract/downloader error (caller will also SKIP per your policy) +audio_ensure_clip_ready() { + clip="$1" + url="${2:-${AUDIO_TAR_URL:-}}" + [ -f "$clip" ] && return 0 + # Try once without forcing network (tarball may already be present) + if [ -n "$url" ]; then + audio_fetch_assets_from_url "$url" >/dev/null 2>&1 || true + [ -f "$clip" ] && return 0 + fi + # Bring network up and retry once + if ! ensure_network_online; then + log_warn "Network unavailable; cannot fetch audio assets for $clip" + return 2 + fi + if [ -n "$url" ]; then + if audio_fetch_assets_from_url "$url" >/dev/null 2>&1; then + [ -f "$clip" ] && return 0 + fi + fi + log_warn "Clip fetch/extract failed for $clip" + return 1 } # ---------- dmesg + mixer dumps ---------- diff --git a/Runner/utils/functestlib.sh b/Runner/utils/functestlib.sh index ae6c690a..4c25bb41 100755 --- a/Runner/utils/functestlib.sh +++ b/Runner/utils/functestlib.sh @@ -289,6 +289,194 @@ check_network_status() { fi } + +# ---- Connectivity probe (0 OK, 2 IP/no-internet, 1 no IP) ---- +# Env overrides: +# NET_PROBE_ROUTE_IP=1.1.1.1 +# NET_PING_HOST=8.8.8.8 +check_network_status_rc() { + net_probe_route_ip="${NET_PROBE_ROUTE_IP:-1.1.1.1}" + net_ping_host="${NET_PING_HOST:-8.8.8.8}" + + if command -v ip >/dev/null 2>&1; then + net_ip_addr="$(ip -4 route get "$net_probe_route_ip" 2>/dev/null \ + | awk 'NR==1{for(i=1;i<=NF;i++) if($i=="src"){print $(i+1); exit}}')" + if [ -z "$net_ip_addr" ]; then + net_ip_addr="$(ip -o -4 addr show scope global up 2>/dev/null \ + | awk 'NR==1{split($4,a,"/"); print a[1]}')" + fi + else + net_ip_addr="" + fi + + if [ -n "$net_ip_addr" ]; then + if command -v ping >/dev/null 2>&1; then + if ping -c 1 -W 2 "$net_ping_host" >/dev/null 2>&1 \ + || ping -c 1 -w 2 "$net_ping_host" >/dev/null 2>&1; then + unset net_probe_route_ip net_ping_host net_ip_addr + return 0 + fi + unset net_probe_route_ip net_ping_host net_ip_addr + return 2 + else + unset net_probe_route_ip net_ping_host net_ip_addr + return 2 + fi + fi + + unset net_probe_route_ip net_ping_host net_ip_addr + return 1 +} + +# ---- Interface snapshot (INFO log only) ---- +net_log_iface_snapshot() { + net_ifc="$1" + [ -n "$net_ifc" ] || { unset net_ifc; return 0; } + + net_admin="DOWN" + net_oper="unknown" + net_carrier="0" + net_ip="none" + + if command -v ip >/dev/null 2>&1 && ip -o link show "$net_ifc" >/dev/null 2>&1; then + if ip -o link show "$net_ifc" | awk -F'[<>]' '{print $2}' | grep -qw UP; then + net_admin="UP" + fi + fi + [ -r "/sys/class/net/$net_ifc/operstate" ] && net_oper="$(cat "/sys/class/net/$net_ifc/operstate" 2>/dev/null)" + [ -r "/sys/class/net/$net_ifc/carrier" ] && net_carrier="$(cat "/sys/class/net/$net_ifc/carrier" 2>/dev/null)" + + if command -v get_ip_address >/dev/null 2>&1; then + net_ip="$(get_ip_address "$net_ifc" 2>/dev/null)" + [ -n "$net_ip" ] || net_ip="none" + fi + + log_info "[NET] ${net_ifc}: admin=${net_admin} oper=${net_oper} carrier=${net_carrier} ip=${net_ip}" + + unset net_ifc net_admin net_oper net_carrier net_ip +} + +# ---- Bring the system online if possible (0 OK, 2 IP/no-internet, 1 no IP) ---- +ensure_network_online() { + check_network_status_rc; net_rc=$? + [ "$net_rc" -eq 0 ] && { unset net_rc; return 0; } + + if command -v systemctl >/dev/null 2>&1 && command -v check_systemd_services >/dev/null 2>&1; then + check_systemd_services NetworkManager systemd-networkd connman || true + fi + + net_had_any_ip=0 + + # -------- Ethernet pass -------- + net_ifaces="" + if command -v get_ethernet_interfaces >/dev/null 2>&1; then + net_ifaces="$(get_ethernet_interfaces 2>/dev/null)" + fi + + for net_ifc in $net_ifaces; do + net_log_iface_snapshot "$net_ifc" + + if command -v is_link_up >/dev/null 2>&1; then + if ! is_link_up "$net_ifc"; then + log_info "[NET] ${net_ifc}: link=down → skipping DHCP" + continue + fi + fi + + log_info "[NET] ${net_ifc}: bringing up and requesting DHCP..." + if command -v bringup_interface >/dev/null 2>&1; then + bringup_interface "$net_ifc" 2 2 || true + fi + + if command -v run_dhcp_client >/dev/null 2>&1; then + run_dhcp_client "$net_ifc" 10 >/dev/null 2>&1 || true + elif command -v try_dhcp_client_safe >/dev/null 2>&1; then + try_dhcp_client_safe "$net_ifc" 8 || true + fi + + net_log_iface_snapshot "$net_ifc" + + check_network_status_rc; net_rc=$? + case "$net_rc" in + 0) log_pass "[NET] ${net_ifc}: internet reachable"; unset net_ifaces net_ifc net_rc net_had_any_ip; return 0 ;; + 2) log_warn "[NET] ${net_ifc}: IP assigned but internet not reachable"; net_had_any_ip=1 ;; + 1) log_info "[NET] ${net_ifc}: still no IP after DHCP attempt" ;; + esac + done + + # -------- Wi-Fi pass -------- + net_wifi="" + if command -v get_wifi_interface >/dev/null 2>&1; then + net_wifi="$(get_wifi_interface 2>/dev/null || echo "")" + fi + if [ -n "$net_wifi" ]; then + net_log_iface_snapshot "$net_wifi" + log_info "[NET] ${net_wifi}: bringing up Wi-Fi..." + + if command -v bringup_interface >/dev/null 2>&1; then + bringup_interface "$net_wifi" 2 2 || true + fi + + net_creds="" + if command -v get_wifi_credentials >/dev/null 2>&1; then + net_creds="$(get_wifi_credentials "" "" 2>/dev/null || true)" + fi + + if [ -n "$net_creds" ]; then + net_ssid="$(printf '%s\n' "$net_creds" | awk '{print $1}')" + net_pass="$(printf '%s\n' "$net_creds" | awk '{print $2}')" + log_info "[NET] ${net_wifi}: trying nmcli/wpa_supplicant for SSID='${net_ssid}'" + if command -v wifi_connect_nmcli >/dev/null 2>&1; then + wifi_connect_nmcli "$net_wifi" "$net_ssid" "$net_pass" || true + fi + if command -v wifi_connect_wpa_supplicant >/dev/null 2>&1; then + wifi_connect_wpa_supplicant "$net_wifi" "$net_ssid" "$net_pass" || true + fi + else + log_info "[NET] ${net_wifi}: no credentials provided → DHCP only" + if command -v run_dhcp_client >/dev/null 2>&1; then + run_dhcp_client "$net_wifi" 10 >/dev/null 2>&1 || true + fi + fi + + net_log_iface_snapshot "$net_wifi" + check_network_status_rc; net_rc=$? + case "$net_rc" in + 0) log_pass "[NET] ${net_wifi}: internet reachable"; unset net_wifi net_ifaces net_ifc net_rc net_had_any_ip net_creds net_ssid net_pass; return 0 ;; + 2) log_warn "[NET] ${net_wifi}: IP assigned but internet not reachable"; net_had_any_ip=1 ;; + 1) log_info "[NET] ${net_wifi}: still no IP after connect/DHCP attempt" ;; + esac + fi + + # -------- DHCP/route/DNS fixup (udhcpc script) -------- + net_script_path="" + if command -v ensure_udhcpc_script >/dev/null 2>&1; then + net_script_path="$(ensure_udhcpc_script 2>/dev/null || echo "")" + fi + if [ -n "$net_script_path" ]; then + log_info "[NET] udhcpc default.script present → refreshing leases" + for net_ifc in $net_ifaces $net_wifi; do + [ -n "$net_ifc" ] || continue + if command -v run_dhcp_client >/dev/null 2>&1; then + run_dhcp_client "$net_ifc" 8 >/dev/null 2>&1 || true + fi + done + check_network_status_rc; net_rc=$? + case "$net_rc" in + 0) log_pass "[NET] connectivity restored after udhcpc fixup"; unset net_script_path net_ifaces net_wifi net_ifc net_rc net_had_any_ip; return 0 ;; + 2) log_warn "[NET] IP present but still no internet after udhcpc fixup"; net_had_any_ip=1 ;; + esac + fi + + if [ "$net_had_any_ip" -eq 1 ] 2>/dev/null; then + unset net_script_path net_ifaces net_wifi net_ifc net_rc net_had_any_ip + return 2 + fi + unset net_script_path net_ifaces net_wifi net_ifc net_rc net_had_any_ip + return 1 +} + + # If the tar file already exists,then function exit. Otherwise function to check the network connectivity and it will download tar from internet. extract_tar_from_url() { url=$1