Skip to content

Commit e10de73

Browse files
authored
ci(qemu): Add QEMU emulator to CI (#9558)
* ci(qemu): Add QEMU emulator to CI * ci(qemu): Fix windows build * ci(qemu): Fix skips * ci(qemu): Skip performance tests * ci(qemu): Disable QEMU tests for now * fix(platform): Fix build script recipe number
1 parent ea27a98 commit e10de73

File tree

17 files changed

+113
-9
lines changed

17 files changed

+113
-9
lines changed

.github/scripts/on-push.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ elif [ "$CHUNK_INDEX" -eq "$CHUNKS_CNT" ]; then
6060
BUILD_PIO=1
6161
fi
6262

63-
if [ "$BUILD_LOG" -le 0 ]; then
63+
if [ -z "$BUILD_LOG" ] || [ "$BUILD_LOG" -le 0 ]; then
6464
BUILD_LOG=0
6565
fi
6666

.github/scripts/sketch_utils.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ function build_sketch(){ # build_sketch <ide_path> <user_path> <path-to-ino> [ex
7878

7979
# Default FQBN options if none were passed in the command line.
8080

81-
esp32_opts="PSRAM=enabled,PartitionScheme=huge_app"
81+
esp32_opts="FlashMode=dio,PSRAM=enabled,PartitionScheme=huge_app"
8282
esp32s2_opts="PSRAM=enabled,PartitionScheme=huge_app"
8383
esp32s3_opts="PSRAM=opi,USBMode=default,PartitionScheme=huge_app"
84-
esp32c3_opts="PartitionScheme=huge_app"
84+
esp32c3_opts="FlashMode=dio,PartitionScheme=huge_app"
8585
esp32c6_opts="PartitionScheme=huge_app"
8686
esp32h2_opts="PartitionScheme=huge_app"
8787

.github/scripts/tests_run.sh

+25-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function run_test() {
88
local sketchdir=$(dirname $sketch)
99
local sketchname=$(basename $sketchdir)
1010

11-
if [[ -f "$sketchdir/.skip.$platform" ]]; then
11+
if [[ -f "$sketchdir/.skip.$platform" ]] || [[ -f "$sketchdir/.skip.$target" ]] || [[ -f "$sketchdir/.skip.$platform.$target" ]]; then
1212
echo "Skipping $sketchname test for $target, platform: $platform"
1313
skipfile="$sketchdir/.test_skipped"
1414
touch $skipfile
@@ -45,11 +45,24 @@ function run_test() {
4545
if [[ -f "$sketchdir/scenario.yaml" ]]; then
4646
extra_args+=" --wokwi-scenario $sketchdir/scenario.yaml"
4747
fi
48+
elif [ $platform == "qemu" ]; then
49+
PATH=$HOME/qemu/bin:$PATH
50+
extra_args="--embedded-services qemu --qemu-image-path $build_dir/$sketchname.ino.merged.bin"
51+
52+
if [ $target == "esp32" ] || [ $target == "esp32s3" ]; then
53+
extra_args+=" --qemu-prog-path qemu-system-xtensa --qemu-cli-args=\"-machine $target -m 4M -nographic\""
54+
elif [ $target == "esp32c3" ]; then
55+
extra_args+=" --qemu-prog-path qemu-system-riscv32 --qemu-cli-args=\"-machine $target -icount 3 -nographic\""
56+
else
57+
echo "Unsupported QEMU target: $target"
58+
exit 1
59+
fi
4860
else
4961
extra_args="--embedded-services esp,arduino"
5062
fi
5163

52-
pytest tests --build-dir $build_dir -k test_$sketchname --junit-xml=$report_file $extra_args
64+
echo "pytest tests --build-dir $build_dir -k test_$sketchname --junit-xml=$report_file $extra_args"
65+
bash -c "pytest tests --build-dir $build_dir -k test_$sketchname --junit-xml=$report_file $extra_args"
5366
result=$?
5467
if [ $result -ne 0 ]; then
5568
return $result
@@ -71,6 +84,13 @@ while [ ! -z "$1" ]; do
7184
-c )
7285
chunk_run=1
7386
;;
87+
-q )
88+
if [ ! -d $QEMU_PATH ]; then
89+
echo "QEMU path $QEMU_PATH does not exist"
90+
exit 1
91+
fi
92+
platform="qemu"
93+
;;
7494
-w )
7595
shift
7696
wokwi_timeout=$1
@@ -113,7 +133,9 @@ while [ ! -z "$1" ]; do
113133
shift
114134
done
115135

116-
source ${SCRIPTS_DIR}/install-arduino-ide.sh
136+
if [ ! $platform == "qemu" ]; then
137+
source ${SCRIPTS_DIR}/install-arduino-ide.sh
138+
fi
117139

118140
# If sketch is provided and test type is not, test type is inferred from the sketch path
119141
if [[ $test_type == "all" ]] || [[ -z $test_type ]]; then

.github/workflows/hil.yml

+78-2
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,83 @@ jobs:
8686
~/.arduino/tests/**/build*.tmp/*.elf
8787
~/.arduino/tests/**/build*.tmp/*.json
8888
89+
qemu-test:
90+
needs: [gen_chunks, build]
91+
name: ${{matrix.chip}}-QEMU_Test#${{matrix.chunks}}
92+
if: ${{ false }}
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
chip: ['esp32', 'esp32c3'] # Currently only ESP32 and ESP32-C3 are supported by QEMU
97+
chunks: ${{fromJson(needs.gen_chunks.outputs.chunks)}}
98+
runs-on: ubuntu-latest
99+
env:
100+
QEMU_INSTALL_PATH: "$HOME"
101+
steps:
102+
- name: Checkout repository
103+
uses: actions/checkout@v4
104+
105+
- name: Get QEMU version
106+
uses: pozetroninc/github-action-get-latest-release@v0.7.0
107+
id: get-qemu-version
108+
with:
109+
token: ${{secrets.GITHUB_TOKEN}}
110+
owner: espressif
111+
repo: qemu
112+
excludes: prerelease, draft
113+
114+
- name: Cache tools
115+
id: cache-linux
116+
uses: actions/cache@v4
117+
with:
118+
path: |
119+
~/qemu
120+
~/.cache/pip
121+
key: qemu-${{ steps.get-qemu-version.outputs.release }}-${{ hashFiles('.github/workflows/hil.yml') }}
122+
123+
- name: Install dependencies
124+
run: |
125+
pip install -U pip
126+
pip install -r tests/requirements.txt --extra-index-url https://dl.espressif.com/pypi
127+
sudo apt update && sudo apt install libpixman-1-0 libnuma1 libglib2.0-0 libslirp0 libsdl2-2.0-0
128+
129+
- name: Download QEMU
130+
if: steps.cache-linux.outputs.cache-hit != 'true'
131+
run: |
132+
cd ${{ env.QEMU_INSTALL_PATH }}
133+
underscore_release=$(echo ${{ steps.get-qemu-version.outputs.release }} | sed 's/\-/_/g')
134+
curl -L https://github.com/espressif/qemu/releases/download/${{ steps.get-qemu-version.outputs.release }}/qemu-riscv32-softmmu-${underscore_release}-x86_64-linux-gnu.tar.xz > qemu-riscv32.tar.xz
135+
curl -L https://github.com/espressif/qemu/releases/download/${{ steps.get-qemu-version.outputs.release }}/qemu-xtensa-softmmu-${underscore_release}-x86_64-linux-gnu.tar.xz > qemu-xtensa.tar.xz
136+
tar -xf qemu-riscv32.tar.xz
137+
tar -xf qemu-xtensa.tar.xz
138+
rm qemu-*
139+
echo "QEMU_PATH=${{ env.QEMU_INSTALL_PATH }}/qemu" >> $GITHUB_ENV
140+
141+
- name: Download ${{matrix.chip}}-${{matrix.chunks}} artifacts
142+
uses: actions/download-artifact@v4
143+
with:
144+
name: ${{matrix.chip}}-${{matrix.chunks}}.artifacts
145+
path: ~/
146+
147+
- name: Run Tests
148+
run: QEMU_PATH="${{env.QEMU_PATH}}" bash .github/scripts/tests_run.sh -c -t ${{matrix.chip}} -i ${{matrix.chunks}} -m ${{env.MAX_CHUNKS}} -q
149+
150+
- name: Check if tests were skipped
151+
id: check-test-skipped
152+
run: |
153+
if [ $(find "tests" -name ".test_skipped") ]; then
154+
echo "skipped=true" >> $GITHUB_OUTPUT
155+
else
156+
echo "skipped=false" >> $GITHUB_OUTPUT
157+
fi
158+
159+
- name: Upload test result artifacts
160+
uses: actions/upload-artifact@v4
161+
if: ${{ always() && steps.check-test-skipped.outputs.skipped == 'false' }}
162+
with:
163+
name: qemu_results-${{matrix.chip}}-${{matrix.chunks}}
164+
path: tests/*/*.xml
165+
89166
wokwi-test:
90167
needs: [gen_chunks, build]
91168
if: github.event_name == 'schedule'
@@ -105,7 +182,7 @@ jobs:
105182
with:
106183
name: ${{matrix.chip}}-${{matrix.chunks}}.artifacts
107184
path: ~/
108-
185+
109186
- name: Install Wokwi CLI
110187
run: curl -L https://wokwi.com/ci/install.sh | sh
111188

@@ -205,4 +282,3 @@ jobs:
205282
with:
206283
name: Event File
207284
path: ${{github.event_path}}
208-

platform.txt

+5
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ recipe.hooks.objcopy.postobjcopy.1.pattern.windows=cmd /c if exist "{build.path}
169169
recipe.hooks.objcopy.postobjcopy.2.pattern=/usr/bin/env bash -c "[ ! -d "{build.path}"/libraries/ESP_SR ] || [ ! -f "{compiler.sdk.path}"/esp_sr/srmodels.bin ] || cp -f "{compiler.sdk.path}"/esp_sr/srmodels.bin "{build.path}"/srmodels.bin"
170170
recipe.hooks.objcopy.postobjcopy.2.pattern.windows=cmd /c if exist "{build.path}\libraries\ESP_SR" if exist "{compiler.sdk.path}\esp_sr\srmodels.bin" COPY /y "{compiler.sdk.path}\esp_sr\srmodels.bin" "{build.path}\srmodels.bin"
171171

172+
# Create merged binary
173+
recipe.hooks.objcopy.postobjcopy.3.pattern_args=--chip {build.mcu} merge_bin -o "{build.path}/{build.project_name}.merged.bin" --fill-flash-size {build.flash_size} --flash_mode keep --flash_freq keep --flash_size keep {build.bootloader_addr} "{build.path}/{build.project_name}.bootloader.bin" 0x8000 "{build.path}/{build.project_name}.partitions.bin" 0xe000 "{runtime.platform.path}/tools/partitions/boot_app0.bin" 0x10000 "{build.path}/{build.project_name}.bin"
174+
recipe.hooks.objcopy.postobjcopy.3.pattern="{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.hooks.objcopy.postobjcopy.3.pattern_args}
175+
recipe.hooks.objcopy.postobjcopy.3.pattern.linux=python3 "{tools.esptool_py.path}/{tools.esptool_py.cmd}" {recipe.hooks.objcopy.postobjcopy.3.pattern_args}
176+
172177
## Save bin
173178
recipe.output.tmp_file={build.project_name}.bin
174179
recipe.output.save_file={build.project_name}.{build.variant}.bin

tests/performance/coremark/.skip.qemu

Whitespace-only changes.

tests/performance/fibonacci/.skip.qemu

Whitespace-only changes.

tests/performance/psramspeed/.skip.qemu

Whitespace-only changes.

tests/performance/ramspeed/.skip.qemu

Whitespace-only changes.

tests/performance/superpi/.skip.qemu

Whitespace-only changes.

tests/pytest.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[pytest]
2-
addopts = --embedded-services esp,arduino,wokwi
2+
addopts = --embedded-services esp,arduino,wokwi,qemu
33

44
# log related
55
log_cli = True

tests/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pytest-cov
44
pytest-embedded-serial-esp>=1.10.2
55
pytest-embedded-arduino>=1.10.2
66
pytest-embedded-wokwi>=1.10.2
7+
pytest-embedded-qemu>=1.10.2

tests/validation/democfg/.skip.qemu

Whitespace-only changes.

tests/validation/nvs/.skip.qemu

Whitespace-only changes.

tests/validation/periman/.skip.qemu

Whitespace-only changes.

tests/validation/touch/.skip.qemu

Whitespace-only changes.

tests/validation/uart/.skip.qemu

Whitespace-only changes.

0 commit comments

Comments
 (0)