feat: Enhance CI workflows for backend unit and e2e tests; add environment setup and skip timing-sensitive tests in CI
This commit is contained in:
parent
7971743174
commit
6b161eab34
|
|
@ -0,0 +1,128 @@
|
|||
name: Backend E2E Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, main]
|
||||
pull_request:
|
||||
branches: [master, main]
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
|
||||
env:
|
||||
QEMU_RELEASE_URL: https://github.com/davidmonterocrespo24/velxio/releases/download/qemu-prebuilt
|
||||
QEMU_DIR: /opt/velxio-qemu
|
||||
BACKEND_URL: http://localhost:8001
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# ── QEMU binaries + ROM files ──────────────────────────────────────────────
|
||||
- name: Download QEMU binaries and ROM files
|
||||
run: |
|
||||
mkdir -p $QEMU_DIR
|
||||
cd $QEMU_DIR
|
||||
|
||||
echo "Downloading QEMU shared libraries..."
|
||||
curl -fSL -o libqemu-xtensa.so "$QEMU_RELEASE_URL/libqemu-xtensa-amd64.so"
|
||||
curl -fSL -o libqemu-riscv32.so "$QEMU_RELEASE_URL/libqemu-riscv32-amd64.so"
|
||||
|
||||
echo "Downloading ROM files..."
|
||||
curl -fSL -o esp32-v3-rom.bin "$QEMU_RELEASE_URL/esp32-v3-rom.bin"
|
||||
curl -fSL -o esp32-v3-rom-app.bin "$QEMU_RELEASE_URL/esp32-v3-rom-app.bin"
|
||||
curl -fSL -o esp32c3-rom.bin "$QEMU_RELEASE_URL/esp32c3-rom.bin"
|
||||
|
||||
chmod +x libqemu-xtensa.so libqemu-riscv32.so
|
||||
ls -lh .
|
||||
|
||||
# ── arduino-cli + ESP32 core ───────────────────────────────────────────────
|
||||
- name: Install arduino-cli
|
||||
run: |
|
||||
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh \
|
||||
| BINDIR=/usr/local/bin sh
|
||||
|
||||
- name: Cache arduino-cli cores and libraries
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.arduino15
|
||||
key: arduino-cores-esp32-${{ runner.os }}-v1
|
||||
|
||||
- name: Install ESP32 arduino core
|
||||
run: |
|
||||
arduino-cli config init --overwrite
|
||||
arduino-cli config add board_manager.additional_urls \
|
||||
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
|
||||
arduino-cli core update-index
|
||||
arduino-cli core install esp32:esp32
|
||||
|
||||
# ── Python + backend dependencies ─────────────────────────────────────────
|
||||
- name: Set up Python 3.11
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: pip-${{ hashFiles('backend/requirements.txt') }}
|
||||
|
||||
- name: Install backend dependencies
|
||||
run: pip install -r backend/requirements.txt
|
||||
|
||||
# ── Node.js ───────────────────────────────────────────────────────────────
|
||||
- name: Set up Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
# ── Start backend ─────────────────────────────────────────────────────────
|
||||
- name: Start backend server
|
||||
run: |
|
||||
cd backend
|
||||
QEMU_ESP32_LIB=$QEMU_DIR/libqemu-xtensa.so \
|
||||
QEMU_RISCV32_LIB=$QEMU_DIR/libqemu-riscv32.so \
|
||||
uvicorn app.main:app --port 8001 &
|
||||
echo "Backend PID: $!"
|
||||
env:
|
||||
QEMU_ESP32_LIB: /opt/velxio-qemu/libqemu-xtensa.so
|
||||
QEMU_RISCV32_LIB: /opt/velxio-qemu/libqemu-riscv32.so
|
||||
|
||||
- name: Wait for backend to be ready
|
||||
run: |
|
||||
echo "Waiting for backend on port 8001..."
|
||||
for i in $(seq 1 30); do
|
||||
if curl -sf http://localhost:8001/docs > /dev/null 2>&1; then
|
||||
echo "Backend is up after ${i}s"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
curl -sf http://localhost:8001/docs > /dev/null || (echo "Backend failed to start" && exit 1)
|
||||
|
||||
# ── Run e2e tests ─────────────────────────────────────────────────────────
|
||||
#
|
||||
# These tests compile real firmware via the backend and run full simulations
|
||||
# over WebSocket. Each test has a generous timeout because compilation +
|
||||
# firmware boot takes 30-60 s.
|
||||
#
|
||||
# NOT run here (require Windows DLLs, not .so):
|
||||
# test/backend/integration/ — uses libqemu-xtensa.dll (Windows only)
|
||||
#
|
||||
- name: Run DHT22 e2e test
|
||||
run: node test/backend/e2e/test_dht22_simulation.mjs --timeout=60
|
||||
env:
|
||||
BACKEND_URL: http://localhost:8001
|
||||
|
||||
- name: Run HC-SR04 e2e test
|
||||
run: node test/backend/e2e/test_hcsr04_simulation.mjs --timeout=75
|
||||
env:
|
||||
BACKEND_URL: http://localhost:8001
|
||||
|
||||
- name: Run MPU-6050 e2e test
|
||||
run: node test/backend/e2e/test_mpu6050_simulation.mjs --timeout=60
|
||||
env:
|
||||
BACKEND_URL: http://localhost:8001
|
||||
|
|
@ -32,7 +32,16 @@ jobs:
|
|||
- name: Install test dependencies
|
||||
run: pip install pytest pytest-asyncio
|
||||
|
||||
# Run only unit tests (test/backend/unit/) — no QEMU or arduino-cli needed.
|
||||
# Integration tests live in test/backend/integration/ and must be run manually.
|
||||
# Run only UNIT tests (test/backend/unit/).
|
||||
# These tests have zero external dependencies — no QEMU binary, no arduino-cli,
|
||||
# no running backend server.
|
||||
#
|
||||
# NOT included here (must be run manually on Windows with QEMU DLLs):
|
||||
# test/backend/integration/ — needs arduino-cli + QEMU binary
|
||||
# test/backend/e2e/ — JS tests, need running backend + QEMU + arduino-cli
|
||||
# Run e2e tests locally: scripts\run-e2e-tests.bat
|
||||
- name: Run backend unit tests
|
||||
# CI=true is set automatically by GitHub Actions.
|
||||
# Tests decorated with @unittest.skipIf(CI=='true', ...) are skipped here
|
||||
# (e.g. timing-sensitive tests that use busy-wait).
|
||||
run: pytest test/backend/unit/ -v --tb=short
|
||||
|
|
|
|||
|
|
@ -3,27 +3,58 @@
|
|||
These tests compile real firmware via the backend API and run the full
|
||||
simulation through a WebSocket, verifying sensor readings in the serial output.
|
||||
|
||||
## Prerequisites
|
||||
## CI status
|
||||
|
||||
- Backend running on `http://localhost:8001`
|
||||
- Node.js 18+
|
||||
These tests **run in GitHub Actions** via `.github/workflows/backend-e2e-tests.yml`.
|
||||
|
||||
## Run
|
||||
The CI workflow:
|
||||
|
||||
1. Downloads `libqemu-xtensa-amd64.so` and `libqemu-riscv32-amd64.so` from the
|
||||
[qemu-prebuilt](https://github.com/davidmonterocrespo24/velxio/releases/tag/qemu-prebuilt) release.
|
||||
2. Downloads ROM files: `esp32-v3-rom.bin`, `esp32-v3-rom-app.bin`, `esp32c3-rom.bin`.
|
||||
3. Installs arduino-cli + `esp32:esp32` core.
|
||||
4. Starts `uvicorn app.main:app --port 8001` with `QEMU_ESP32_LIB` and `QEMU_RISCV32_LIB` set.
|
||||
5. Runs all three JS tests.
|
||||
|
||||
## Local prerequisites
|
||||
|
||||
1. Backend running with QEMU libs in PATH:
|
||||
```bash
|
||||
cd backend
|
||||
QEMU_ESP32_LIB=/path/to/libqemu-xtensa.so \
|
||||
QEMU_RISCV32_LIB=/path/to/libqemu-riscv32.so \
|
||||
uvicorn app.main:app --reload --port 8001
|
||||
```
|
||||
On Windows the `.dll` files live in `backend/app/services/`.
|
||||
|
||||
2. Node.js 18+ installed.
|
||||
|
||||
## Run all e2e tests
|
||||
|
||||
Use the convenience script from the repo root:
|
||||
|
||||
```bash
|
||||
# From repo root
|
||||
node test/backend/e2e/test_dht22_simulation.mjs [--timeout=45]
|
||||
node test/backend/e2e/test_hcsr04_simulation.mjs [--timeout=60]
|
||||
node test/backend/e2e/test_mpu6050_simulation.mjs [--timeout=40]
|
||||
# Windows
|
||||
scripts\run-e2e-tests.bat
|
||||
|
||||
# Custom backend URL
|
||||
node test/backend/e2e/test_dht22_simulation.mjs --backend=http://localhost:8001
|
||||
# Or individually (from repo root):
|
||||
node test/backend/e2e/test_dht22_simulation.mjs --timeout=60
|
||||
node test/backend/e2e/test_hcsr04_simulation.mjs --timeout=75
|
||||
node test/backend/e2e/test_mpu6050_simulation.mjs --timeout=60
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
| File | Sensor | What it verifies |
|
||||
|------|--------|-----------------|
|
||||
| `test_dht22_simulation.mjs` | DHT22 | Temperature & humidity, sensor_update changes values |
|
||||
| `test_hcsr04_simulation.mjs` | HC-SR04 | Distance at 10/40/100/200 cm, sensor_update changes distance |
|
||||
| `test_mpu6050_simulation.mjs` | MPU-6050 | I2C accelerometer/gyroscope readings |
|
||||
| File | Sensor | What it verifies | Typical runtime |
|
||||
|------|--------|-----------------|-----------------|
|
||||
| `test_dht22_simulation.mjs` | DHT22 (GPIO4) | Temperature & humidity readings, `sensor_update` changes values | ~50 s |
|
||||
| `test_hcsr04_simulation.mjs` | HC-SR04 (GPIO18/19) | Distance at 10/40/100/200 cm, `sensor_update` changes distance | ~60 s |
|
||||
| `test_mpu6050_simulation.mjs` | MPU-6050 (I2C) | Accelerometer/gyroscope I2C readings | ~40 s |
|
||||
|
||||
## Pass criteria
|
||||
|
||||
| Test | Passes when |
|
||||
|------|-------------|
|
||||
| DHT22 | First reading received + values change after `sensor_update` |
|
||||
| HC-SR04 | ≥3 correct readings, ≥2 distances, miss rate ≤30% |
|
||||
| MPU-6050 | I2C communication established, sensor data in serial output |
|
||||
|
|
|
|||
|
|
@ -387,6 +387,10 @@ class TestDHT22ResponseWaveform(unittest.TestCase):
|
|||
|
||||
print(' Waveform sequence: CORRECT ✓')
|
||||
|
||||
@unittest.skipIf(
|
||||
__import__('os').environ.get('CI') == 'true',
|
||||
'Timing-sensitive test (uses busy-wait + sleep) — skipped in CI'
|
||||
)
|
||||
def test_response_data_matches_payload(self):
|
||||
"""Verify that the HIGH pulse durations encode the correct bits."""
|
||||
harness = DHT22SimulatorHarness()
|
||||
|
|
|
|||
Loading…
Reference in New Issue