#!/bin/bash # # validate-ios-logs.sh - Validates prefetch log sequence for iOS DailyNotificationPlugin # # Purpose: Automatically validates that all critical log steps occurred in proper order # for a complete prefetch cycle (registration → scheduling → execution → delivery) # # Usage: # # From log file # ./scripts/validate-ios-logs.sh device.log # # # From stdin (grep filtered) # grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log | ./scripts/validate-ios-logs.sh # # # From Xcode console output # xcrun simctl spawn booted log stream --predicate 'subsystem == "com.timesafari.dailynotification"' | ./scripts/validate-ios-logs.sh # # Author: Matthew Raymer # Date: 2025-11-15 # Status: Phase 1 - Log sequence validation set -euo pipefail # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Expected sequence markers (in order) REGISTRATION="Registering BGTaskScheduler task" SCHEDULING="BGAppRefreshTask scheduled" HANDLER="BGTask handler invoked" FETCH_START="Starting fetch" FETCH_SUCCESS="Fetch success" TASK_COMPLETE="Task completed" NOTIFICATION="Notification delivered" # Optional markers (not required but checked if present) PREFETCH_SCHEDULED="Scheduling prefetch for notification" CONTENT_CACHED="Cached content for scheduleId" USING_CACHED="Using cached content for notification" # Determine input source if [ $# -eq 0 ]; then # Read from stdin LOG_FILE="/dev/stdin" INPUT_SOURCE="stdin" elif [ "$1" = "-" ]; then # Explicit stdin LOG_FILE="/dev/stdin" INPUT_SOURCE="stdin" else # Read from file LOG_FILE="$1" INPUT_SOURCE="file: $LOG_FILE" if [ ! -f "$LOG_FILE" ]; then echo -e "${RED}❌ Error: Log file not found: $LOG_FILE${NC}" >&2 exit 1 fi fi # Track which markers were found FOUND_REGISTRATION=false FOUND_SCHEDULING=false FOUND_HANDLER=false FOUND_FETCH_START=false FOUND_FETCH_SUCCESS=false FOUND_TASK_COMPLETE=false FOUND_NOTIFICATION=false # Track optional markers FOUND_PREFETCH_SCHEDULED=false FOUND_CONTENT_CACHED=false FOUND_USING_CACHED=false # Read log file and check for markers while IFS= read -r line || [ -n "$line" ]; do # Check required markers if echo "$line" | grep -q "$REGISTRATION"; then FOUND_REGISTRATION=true fi if echo "$line" | grep -q "$SCHEDULING"; then FOUND_SCHEDULING=true fi if echo "$line" | grep -q "$HANDLER"; then FOUND_HANDLER=true fi if echo "$line" | grep -q "$FETCH_START"; then FOUND_FETCH_START=true fi if echo "$line" | grep -q "$FETCH_SUCCESS"; then FOUND_FETCH_SUCCESS=true fi if echo "$line" | grep -q "$TASK_COMPLETE"; then FOUND_TASK_COMPLETE=true fi if echo "$line" | grep -q "$NOTIFICATION"; then FOUND_NOTIFICATION=true fi # Check optional markers if echo "$line" | grep -q "$PREFETCH_SCHEDULED"; then FOUND_PREFETCH_SCHEDULED=true fi if echo "$line" | grep -q "$CONTENT_CACHED"; then FOUND_CONTENT_CACHED=true fi if echo "$line" | grep -q "$USING_CACHED"; then FOUND_USING_CACHED=true fi done < "$LOG_FILE" # Validate required sequence MISSING_MARKERS=() if [ "$FOUND_REGISTRATION" = false ]; then MISSING_MARKERS+=("Registration") fi if [ "$FOUND_SCHEDULING" = false ]; then MISSING_MARKERS+=("Scheduling") fi if [ "$FOUND_HANDLER" = false ]; then MISSING_MARKERS+=("Handler") fi if [ "$FOUND_FETCH_START" = false ]; then MISSING_MARKERS+=("Fetch Start") fi if [ "$FOUND_FETCH_SUCCESS" = false ]; then MISSING_MARKERS+=("Fetch Success") fi if [ "$FOUND_TASK_COMPLETE" = false ]; then MISSING_MARKERS+=("Task Complete") fi if [ "$FOUND_NOTIFICATION" = false ]; then MISSING_MARKERS+=("Notification") fi # Output results echo "📋 Log Sequence Validation Report" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "Input: $INPUT_SOURCE" echo "" # Required markers status echo "Required Sequence Markers:" if [ ${#MISSING_MARKERS[@]} -eq 0 ]; then echo -e " ${GREEN}✅ Registration${NC} - BGTask registered" echo -e " ${GREEN}✅ Scheduling${NC} - BGTask scheduled" echo -e " ${GREEN}✅ Handler${NC} - BGTask handler invoked" echo -e " ${GREEN}✅ Fetch Start${NC} - Fetch operation started" echo -e " ${GREEN}✅ Fetch Success${NC} - Fetch completed successfully" echo -e " ${GREEN}✅ Task Complete${NC} - BGTask marked complete" echo -e " ${GREEN}✅ Notification${NC} - Notification delivered" echo "" echo -e "${GREEN}✅ Log sequence validated: All required steps present${NC}" else echo -e " ${GREEN}✅ Registration${NC} - BGTask registered" || echo -e " ${RED}❌ Registration${NC} - MISSING" echo -e " ${GREEN}✅ Scheduling${NC} - BGTask scheduled" || echo -e " ${RED}❌ Scheduling${NC} - MISSING" echo -e " ${GREEN}✅ Handler${NC} - BGTask handler invoked" || echo -e " ${RED}❌ Handler${NC} - MISSING" echo -e " ${GREEN}✅ Fetch Start${NC} - Fetch operation started" || echo -e " ${RED}❌ Fetch Start${NC} - MISSING" echo -e " ${GREEN}✅ Fetch Success${NC} - Fetch completed successfully" || echo -e " ${RED}❌ Fetch Success${NC} - MISSING" echo -e " ${GREEN}✅ Task Complete${NC} - BGTask marked complete" || echo -e " ${RED}❌ Task Complete${NC} - MISSING" echo -e " ${GREEN}✅ Notification${NC} - Notification delivered" || echo -e " ${RED}❌ Notification${NC} - MISSING" echo "" echo -e "${RED}❌ Log sequence incomplete: Missing ${#MISSING_MARKERS[@]} step(s)${NC}" echo "" echo "Missing markers:" for marker in "${MISSING_MARKERS[@]}"; do echo -e " ${RED} • $marker${NC}" done fi echo "" # Optional markers status echo "Optional Markers (for enhanced validation):" if [ "$FOUND_PREFETCH_SCHEDULED" = true ]; then echo -e " ${GREEN}✅ Prefetch Scheduled${NC} - Prefetch scheduling logged" else echo -e " ${YELLOW}⚠️ Prefetch Scheduled${NC} - Not found (optional)" fi if [ "$FOUND_CONTENT_CACHED" = true ]; then echo -e " ${GREEN}✅ Content Cached${NC} - Content cached after fetch" else echo -e " ${YELLOW}⚠️ Content Cached${NC} - Not found (optional)" fi if [ "$FOUND_USING_CACHED" = true ]; then echo -e " ${GREEN}✅ Using Cached${NC} - Notification used cached content" else echo -e " ${YELLOW}⚠️ Using Cached${NC} - Not found (optional)" fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # Exit with appropriate code if [ ${#MISSING_MARKERS[@]} -eq 0 ]; then exit 0 else exit 1 fi