🛑 Add QEMU-based E2E testing with Playwright using V4 Mainline Ethernet Debug build (16MB, QIO flash, WLED_QEMU workaround) with enhanced network diagnostics #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: QEMU E2E Testing | |
| on: | |
| pull_request: | |
| branches: [ mdev, main ] | |
| push: | |
| branches: [ mdev, main ] | |
| workflow_dispatch: | |
| jobs: | |
| # Job 1: Build firmware for QEMU testing | |
| build-firmware: | |
| name: Build ESP32 Firmware for QEMU | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache pip | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip- | |
| - name: Cache PlatformIO | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.platformio | |
| key: ${{ runner.os }}-pio-esp32_16MB_V4_M_eth_debug-${{ hashFiles('**/platformio.ini') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pio-esp32_16MB_V4_M_eth_debug- | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.9' | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install PlatformIO | |
| run: pip install -r requirements.txt | |
| - name: Install Node.js dependencies | |
| run: npm ci | |
| - name: Build Web UI | |
| run: npm run build | |
| - name: Build ESP32 firmware | |
| run: pio run -e esp32_16MB_V4_M_eth_debug | |
| - name: Upload firmware artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: esp32-firmware | |
| path: .pio/build/esp32_16MB_V4_M_eth_debug/ | |
| retention-days: 1 | |
| # Job 2: Test with QEMU ESP32 | |
| test-qemu: | |
| name: QEMU E2E Tests | |
| runs-on: ubuntu-22.04 | |
| needs: build-firmware | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.9' | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Download firmware artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: esp32-firmware | |
| path: .pio/build/esp32_16MB_V4_M_eth_debug/ | |
| - name: Install Node.js dependencies | |
| run: npm ci | |
| - name: Install Playwright Browsers | |
| run: npx playwright install --with-deps chromium | |
| - name: Install ESP32 exception decoder | |
| run: | | |
| pip install esptool | |
| # Install the exception decoder from platformio | |
| pip install platformio | |
| # The xtensa toolchain should be available from the firmware build artifacts | |
| - name: Install QEMU dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libsdl2-2.0-0 libpixman-1-0 libglib2.0-0 binutils | |
| - name: Setup QEMU ESP32 | |
| run: | | |
| bash .github/scripts/setup-qemu.sh | |
| - name: Make decoder script executable | |
| run: | | |
| chmod +x .github/scripts/monitor-qemu.py | |
| - name: Start QEMU with WLED firmware in background | |
| run: | | |
| chmod +x .github/scripts/run-qemu.sh | |
| bash .github/scripts/run-qemu.sh .pio/build/esp32_16MB_V4_M_eth_debug qemu-esp32 8080 > qemu-output.log 2>&1 & | |
| echo "Waiting for QEMU to start and WLED to boot..." | |
| sleep 45 | |
| - name: Check QEMU status and wait for HTTP server | |
| run: | | |
| if [ ! -f qemu.pid ]; then | |
| echo "ERROR: qemu.pid not found" | |
| echo "=== QEMU Output (last 200 lines) ===" | |
| tail -200 qemu-output.log || true | |
| exit 1 | |
| fi | |
| QEMU_PID=$(cat qemu.pid) | |
| if ! kill -0 $QEMU_PID 2>/dev/null; then | |
| echo "ERROR: QEMU process not running" | |
| echo "=== QEMU Output (last 200 lines) ===" | |
| tail -200 qemu-output.log || true | |
| exit 1 | |
| fi | |
| echo "QEMU is running (PID: $QEMU_PID)" | |
| echo "Testing if WLED HTTP server is responding..." | |
| # Wait up to 2 minutes for HTTP server to respond | |
| for i in {1..60}; do | |
| if curl -f -m 5 http://localhost:8080/ > /dev/null 2>&1; then | |
| echo "SUCCESS: WLED HTTP server is responding!" | |
| exit 0 | |
| fi | |
| echo "Attempt $i/60: Waiting for HTTP server..." | |
| sleep 2 | |
| done | |
| echo "ERROR: HTTP server not responding after 2 minutes" | |
| echo "=== QEMU Output (last 200 lines) ===" | |
| tail -200 qemu-output.log || true | |
| echo "" | |
| echo "=== Checking for ESP32 exceptions/crashes ===" | |
| if grep -i "exception\|abort\|backtrace\|panic" qemu-output.log; then | |
| echo "FOUND: Firmware crash detected in QEMU output" | |
| else | |
| echo "No obvious crash patterns found" | |
| fi | |
| exit 1 | |
| - name: Run Playwright tests against QEMU | |
| env: | |
| WLED_BASE_URL: http://localhost:8080 | |
| run: npm run test:e2e | |
| - name: Analyze QEMU output for crashes | |
| if: always() | |
| run: | | |
| echo "=== Analyzing QEMU output for ESP32 crashes ===" | |
| if [ -f qemu-output.log ]; then | |
| if grep -i "exception\|abort\|backtrace\|panic\|guru meditation" qemu-output.log > /dev/null; then | |
| echo "ESP32 Exception/Crash detected in QEMU output!" | |
| echo "" | |
| echo "=== Exception Context ===" | |
| grep -A 20 -B 5 -i "exception\|abort\|backtrace\|panic\|guru meditation" qemu-output.log | head -100 | |
| echo "" | |
| echo "Note: This could be a QEMU-specific issue or a real firmware bug." | |
| echo "QEMU ESP32 emulation has limitations:" | |
| echo " - Many peripherals are not fully emulated" | |
| echo " - Some hardware features may cause crashes in QEMU but work on real hardware" | |
| echo " - Network/WiFi emulation is limited" | |
| else | |
| echo "No ESP32 exceptions detected in QEMU output" | |
| fi | |
| else | |
| echo "No QEMU output log found" | |
| fi | |
| - name: Upload QEMU logs | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: qemu-logs | |
| path: qemu-output.log | |
| retention-days: 7 | |
| - name: Upload Playwright report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: playwright-report | |
| path: playwright-report/ | |
| retention-days: 7 | |
| - name: Stop QEMU | |
| if: always() | |
| run: | | |
| if [ -f qemu.pid ]; then | |
| QEMU_PID=$(cat qemu.pid) | |
| echo "Stopping QEMU (PID: $QEMU_PID)" | |
| kill $QEMU_PID || true | |
| sleep 2 | |
| kill -9 $QEMU_PID 2>/dev/null || true | |
| fi |