#!/usr/bin/env bash # ============================================================================= # Download Firebase Test Lab Results # ============================================================================= # Downloads and organizes test results from Firebase Test Lab, including # screenshots, videos, performance metrics, and test reports. # # Usage: # ./download_results.sh [options] # # Options: # --project-id Firebase project ID (default: kordant-android) # --matrix-id Specific matrix ID to download (optional, downloads latest) # --output-dir Output directory (default: ./test_results) # --download-all Download all artifacts including screenshots and videos # --help Show this help message # ============================================================================= set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Default values PROJECT_ID="${FIREBASE_PROJECT_ID:-kordant-android}" MATRIX_ID="" OUTPUT_DIR="${SCRIPT_DIR}/test_results" DOWNLOAD_ALL=false # ============================================================ # Parse arguments # ============================================================ while [[ $# -gt 0 ]]; do case "$1" in --project-id) PROJECT_ID="$2" shift 2 ;; --matrix-id) MATRIX_ID="$2" shift 2 ;; --output-dir) OUTPUT_DIR="$2" shift 2 ;; --download-all) DOWNLOAD_ALL=true shift ;; --help) grep "^#" "$0" | grep -v "^#!/" | sed 's/^# //' exit 0 ;; *) echo "Unknown option: $1" echo "Usage: $0 --help" exit 1 ;; esac done # ============================================================ # Validate gcloud # ============================================================ if ! command -v gcloud &> /dev/null; then echo "Error: gcloud CLI is not installed." exit 1 fi # ============================================================ # Find the GCS bucket for test results # ============================================================ echo "🔍 Finding Firebase Test Lab results bucket..." echo "Project ID: $PROJECT_ID" # Get the storage bucket name from the Firebase project # Test Lab results are stored in gs://-test-lab- RESULTS_BUCKET=$(gsutil ls 2>/dev/null | grep "${PROJECT_ID}-test-lab-" || echo "") if [ -z "$RESULTS_BUCKET" ]; then echo "No test lab bucket found via gsutil. Trying gcloud to list recent matrices..." echo "" fi # ============================================================ # List recent test matrices # ============================================================ echo "📋 Recent test matrices:" echo "" RECENT_MATRICES=$(gcloud firebase test android matrices list \ --project "$PROJECT_ID" \ --limit 10 \ --format="table(matrixId, state, gcsPath, createTime)" 2>/dev/null || echo "No matrices found.") echo "$RECENT_MATRICES" echo "" # ============================================================ # If no matrix ID specified, get the latest # ============================================================ if [ -z "$MATRIX_ID" ]; then MATRIX_ID=$(gcloud firebase test android matrices list \ --project "$PROJECT_ID" \ --limit 1 \ --format="value(matrixId)" 2>/dev/null || echo "") fi if [ -z "$MATRIX_ID" ]; then echo "No test matrices found. Run tests first." exit 1 fi echo "Selected matrix: $MATRIX_ID" echo "" # ============================================================ # Get GCS path for this matrix # ============================================================ MATRIX_INFO=$(gcloud firebase test android matrices describe "$MATRIX_ID" \ --project "$PROJECT_ID" \ --format="json" 2>/dev/null || echo "{}") GCS_PATH=$(echo "$MATRIX_INFO" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('gcsPath',''))" 2>/dev/null || echo "") if [ -z "$GCS_PATH" ]; then echo "Error: Could not determine GCS path for matrix $MATRIX_ID" exit 1 fi echo "GCS Path: $GCS_PATH" echo "" # ============================================================ # Create output directory # ============================================================ mkdir -p "$OUTPUT_DIR" # ============================================================ # Download results summary (JUnit XML) # ============================================================ echo "📄 Downloading test results summary..." echo " Output: $OUTPUT_DIR/" # Download the test_results.xml (JUnit format) gsutil -m cp "$GCS_PATH/**/test_result.xml" "$OUTPUT_DIR/" 2>/dev/null || true gsutil -m cp "$GCS_PATH/**/test_results.xml" "$OUTPUT_DIR/" 2>/dev/null || true # Download the performance metrics gsutil -m cp "$GCS_PATH/**/performance_metrics.json" "$OUTPUT_DIR/performance/" 2>/dev/null || true # Download the logcat output (if available) gsutil -m cp "$GCS_PATH/**/logcat" "$OUTPUT_DIR/logcat/" 2>/dev/null || true # ============================================================ # Download screenshots and videos (if --download-all) # ============================================================ if [ "$DOWNLOAD_ALL" = true ]; then echo "" echo "🖼️ Downloading screenshots and videos..." # Download all PNG screenshots mkdir -p "$OUTPUT_DIR/screenshots" gsutil -m cp "$GCS_PATH/**/*.png" "$OUTPUT_DIR/screenshots/" 2>/dev/null || true SCREENSHOT_COUNT=$(find "$OUTPUT_DIR/screenshots" -name "*.png" 2>/dev/null | wc -l | tr -d ' ') echo " Screenshots downloaded: $SCREENSHOT_COUNT" # Download all MP4 videos mkdir -p "$OUTPUT_DIR/videos" gsutil -m cp "$GCS_PATH/**/*.mp4" "$OUTPUT_DIR/videos/" 2>/dev/null || true VIDEO_COUNT=$(find "$OUTPUT_DIR/videos" -name "*.mp4" 2>/dev/null | wc -l | tr -d ' ') echo " Videos downloaded: $VIDEO_COUNT" # Download crawl maps (Robo test output) mkdir -p "$OUTPUT_DIR/crawl_maps" gsutil -m cp "$GCS_PATH/**/*.json" "$OUTPUT_DIR/crawl_maps/" 2>/dev/null || true CRAWL_COUNT=$(find "$OUTPUT_DIR/crawl_maps" -name "*.json" 2>/dev/null | wc -l | tr -d ' ') echo " Crawl maps downloaded: $CRAWL_COUNT" fi # ============================================================ # Generate report # ============================================================ echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "📊 Results Summary" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # Parse matrix info for summary MATRIX_STATE=$(echo "$MATRIX_INFO" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('state','UNKNOWN'))" 2>/dev/null || echo "UNKNOWN") echo "Matrix State: $MATRIX_STATE" echo "" # Show outcome summary per device echo "$MATRIX_INFO" | python3 -c " import sys, json d = json.load(sys.stdin) tests = d.get('testExecutions', []) for t in tests: device = t.get('device', {}) model = device.get('androidModelId', '?') version = device.get('androidVersionId', '?') state = t.get('state', '?') outcome = t.get('outcome', {}).get('summary', '?') print(f' {model} (API {version}): {state} - {outcome}') " 2>/dev/null || echo " (Could not parse individual device results)" echo "" echo "Output directory: $OUTPUT_DIR" echo "" echo "View in Firebase Console:" echo " https://console.firebase.google.com/project/$PROJECT_ID/testlab/histories" # ============================================================ # Check for failures # ============================================================ if echo "$MATRIX_STATE" | grep -qi "fail\|error\|invalid"; then echo "" echo "⚠️ Test matrix has failures! Review the results." exit 1 else echo "" echo "✅ Test matrix completed successfully!" exit 0 fi