This guide is optimized for contributors who want a quick, repeatable way to validate changes.
From the repository root:
. $IDF_PATH/export.sh
idf.py set-target esp32s3
idf.py build
idf.py -p /dev/ttyUSB0 flash
python3 -m pip install pyserial
python3 tools/test_integration.py --port /dev/ttyUSB0 --baud 115200Pass criteria:
- Build completes without errors
- Integration script reports all checks as passed
If you are using a different board, change target and serial port accordingly.
ESP32OS uses a three-tier test approach:
| Tier | Method | When |
|---|---|---|
| Unit | Host-side mocks + Unity framework | During development |
| Integration | Hardware-in-the-loop via UART shell | Before every release |
| System | Full soak test on real hardware | Nightly / pre-release |
ESP-IDF includes the unity test framework. This repository does not currently ship host-side unit tests, so the primary automated check is the integration script in tools/.
CI sanity checks validate the test harness itself with:
python -m py_compile tools/test_integration.pypython -m py_compile tools/test_shell_host_integration.pypython -m py_compile tools/test_build_health.pypython tools/test_shell_host_integration.pypython tools/test_integration.py --help
This repository includes tools/test_build_health.py to validate build artifacts and enforce size budgets without hardware.
From the project root after idf.py build:
python3 tools/test_build_health.py --target esp32The script verifies:
- required artifacts exist (
.bin,.elf,.map, bootloader, partition table) - app binary fits in the factory partition with minimum free headroom
- IRAM and DRAM usage percentages from
idf_size.pystay under budget - expected core component libraries are present in the linker map
This repository includes an offline host-side integration runner for shell command workflows that do not require hardware access.
From the project root:
python3 tools/test_shell_host_integration.pyCovered command workflows:
envexportunsetprintenvrunateveryjobskilljob
From the project root:
python3 -m pip install pyserial
python3 tools/test_integration.py --port /dev/ttyUSB0 --baud 115200The script exercises shell, filesystem, logging, GPIO, ADC, and NVS commands over the serial console.
Connect to the device via UART or Telnet and run each test sequence manually or via a script.
Run:
python3 -m pip install pyserial
python3 tools/test_integration.py --port /dev/ttyUSB0For manual validation, the shell prompt should accept help, ps, free, ls, wifi status, and dmesg after boot.
The shell exposes built-in component test runners:
esp32os> test mqtt
esp32os> test ipc
esp32os> test ota
esp32os> test pwm
esp32os> test timer
esp32os> test env
esp32os> test sched
esp32os> test all
Use test all as a quick regression pass after changes in os_mqtt, os_ipc, os_ota, os_pwm, os_timer, os_env, or os_scheduler.
Validate both text and binary publish paths:
esp32os> mqtt config mqtt://broker.hivemq.com
esp32os> mqtt connect
esp32os> mqtt pub dev/status online -q 1
esp32os> mqtt pubhex dev/raw DEADBEEF -q 0
mqtt pub is text-oriented; mqtt pubhex is the binary-safe path for payloads with embedded null bytes.
Before opening a pull request, run and verify:
idf.py set-target esp32 && idf.py buildidf.py set-target esp32s3 && idf.py buildpython3 tools/test_integration.py --port <your-port>on at least one real board
This matches what CI validates on PRs and what release automation validates on master.
# Watch free heap over 1 hour of command cycling
esp32os> free
esp32os> ps
esp32os> top
# ... repeat in a loop via test script
# Heap should remain stable (±2 KB acceptable)Expected: No monotonic decrease in free output.
# Terminal 1:
telnet <esp32-ip> 2222
# Terminal 2 (simultaneously):
telnet <esp32-ip> 2222
# Both sessions should work independently
# Run `ps` in each — output should show both telnet tasksesp32os> wifi connect MySSID MyPass
esp32os> wifi status # confirm connected
# Power-cycle the router or disable/enable WiFi
# Observe: system should auto-reconnect within 30s
esp32os> wifi status # should show Connected again# Simulate watchdog timeout by suspending sys_monitor:
esp32os> ps
esp32os> suspend <pid-of-sys_monitor>
# Wait 30 seconds
# Expected: system reboot with "task watchdog" reset reason
# After reboot:
esp32os> uname -a # should print normally# Write files
esp32os> write /etc/hostname myesp32
esp32os> write /etc/notes.txt "persistent data"
# Reboot
esp32os> reboot
# After reboot, verify files persist
esp32os> cat /etc/hostname # should print: myesp32
esp32os> cat /etc/notes.txt # should print: persistent dataConnect any I2C device (e.g., SSD1306 OLED at 0x3C):
esp32os> i2c scan 21 22
# Expected output includes: 3c# With 1.65V reference on ADC channel 0 (GPIO36):
esp32os> adc readv 0
# Expected: ~1650 mV (±50 mV with proper calibration)Connect GPIO2 → GPIO4 with a jumper:
esp32os> gpio mode 2 out
esp32os> gpio mode 4 in
esp32os> gpio write 2 1
esp32os> gpio read 4 # expected: 1
esp32os> gpio write 2 0
esp32os> gpio read 4 # expected: 0| Metric | Target | Measurement Method |
|---|---|---|
| Shell response latency | < 5 ms | time wrapper on test script |
| WiFi connect time | < 10 s | Log timestamp delta |
| Process create time | < 1 ms | esp_timer_get_time() before/after |
| Log write (no file) | < 50 µs | Timer around OS_LOGI |
| SPIFFS write 256B | < 10 ms | Timer around os_fs_write_file |
| ADC read (×4 avg) | < 1 ms | Timer |
For automated checks in this repository:
- Pull requests to
masterrun build + harness sanity checks via.github/workflows/pr-checks.yml - Pushes to
masterrun build + release pipeline via.github/workflows/master-release.yml
Hardware-specific tests (GPIO wiring, ADC voltage verification, WiFi environment behavior) still require real devices.
If you want to add emulator-based tests later, use QEMU as an additional tier:
# .github/workflows/build.yml
name: Build & Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
container: espressif/idf:v5.2
steps:
- uses: actions/checkout@v3
- run: idf.py set-target esp32
- run: idf.py build
- name: Run unit tests (QEMU)
run: |
idf.py -C test/ build
python tools/run_tests_qemu.pyNote: Full hardware tests (WiFi, ADC, I2C) require real hardware. Use a self-hosted runner with a connected ESP32 for those.
When filing a bug report, include:
- Output of
uname -a - Output of
freeandtop - Output of
dmesg 50at time of issue - Steps to reproduce
- Expected vs actual behaviour
- IDF version (
idf.py --version)