From 68eb523bebdedff12a2c694a18d3dcd74a19f026 Mon Sep 17 00:00:00 2001 From: Oleg Kalachev Date: Fri, 28 Aug 2026 19:29:40 +0300 Subject: [PATCH] Add tests to ci Test pyflix and simulation using pytest. Fix running the sim in non-tty environment. Test presence of some essential files in the docs. --- .github/workflows/build.yml | 11 +++++---- .github/workflows/docs.yml | 5 ++++ gazebo/Arduino.h | 3 ++- tools/requirements.txt | 1 + tools/test.py | 47 +++++++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100755 tools/test.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 743662c..0618eca 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -84,15 +84,16 @@ jobs: run: sudo apt-get install -y libsdl2-dev - name: Build simulator run: make build_simulator - - name: Run simulator + - name: Install Python requirements + run: sudo apt install -y python3-pip && pip3 install -r tools/requirements.txt && pip3 install pytest + - name: Run simulator and tests env: GAZEBO_MODEL_PATH: ${{ github.workspace }}/gazebo/models GAZEBO_PLUGIN_PATH: ${{ github.workspace }}/gazebo/build + GAZEBO_MODEL_DATABASE_URI: '' # disable downloading models run: | - OUT=$(timeout -k 10s 120s gzserver --verbose gazebo/flix.world 2>&1 | tee /dev/stderr) - if echo "$OUT" | grep -Pq "\[Err\](?! \[RenderEngine)"; then - exit 1 - fi + gzserver --verbose gazebo/flix.world & + pytest --capture=no --verbose tools/test.py - uses: actions/upload-artifact@v7 with: name: gazebo-plugin-binary diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 67dcbfa..4e3178d 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -83,6 +83,11 @@ jobs: ln -s "$FQBN/flix.ino.bin" "flix.$BOARD.bin" ln -s "$FQBN/flix.ino.bootloader.bin" "flix.$BOARD.bootloader.bin" done + - name: Test build artifacts + working-directory: docs/build + run: | + ls; ls index.html gyro.html geometry.html firmware.html flix.esp32.merged.bin flix.esp32c3.merged.bin \ + flix.esp32s3.merged.bin flix.esp32s3.opi.merged.bin flix.esp32s3.qspi.merged.bin flix.flix2.merged.bin - name: Upload artifact uses: actions/upload-pages-artifact@v5 with: diff --git a/gazebo/Arduino.h b/gazebo/Arduino.h index 6122225..862d243 100644 --- a/gazebo/Arduino.h +++ b/gazebo/Arduino.h @@ -134,8 +134,9 @@ public: int available() { // to implement for Windows, see https://stackoverflow.com/a/71992965/6850197 + if (!isatty(STDIN_FILENO)) return 0; struct pollfd pfd = { .fd = STDIN_FILENO, .events = POLLIN }; - return poll(&pfd, 1, 0) > 0; + return poll(&pfd, 1, 0) > 0 && (pfd.revents & POLLIN); } int read() { diff --git a/tools/requirements.txt b/tools/requirements.txt index 6b3338b..adff73d 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,3 +1,4 @@ +pymavlink docopt matplotlib mcap diff --git a/tools/test.py b/tools/test.py new file mode 100755 index 0000000..c23e4c4 --- /dev/null +++ b/tools/test.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +# Script for testing pyflix and the simulation. + +from pytest import approx +from math import isnan, isfinite +import time +from pyflix import Flix + +def test(): + print('=== Connect...') + flix = Flix(timeout=20) + + print('=== Check initial state') + time.sleep(1) # give more time for initial state + assert flix.connected + assert flix.mode == 'STAB' + assert not flix.armed + assert flix.landed + assert isnan(flix.voltage) or flix.voltage == approx(4.2) + assert flix.rates == approx((0, 0, 0), abs=0.01) + assert flix.attitude == approx((1, 0, 0, 0), abs=0.01) + assert flix.attitude_euler == approx((0, 0, 0), abs=0.01) + assert all(m == 0 for m in flix.motors) + assert flix.acc == approx((0, 0, 9.81), abs=0.1) + assert flix.gyro == approx((0, 0, 0), abs=0.01) + assert all(ch == 0 for ch in flix.channels) + + print('=== Check console commands') + assert 'Time: ' in flix.cli('time') + assert 'landed: 1' in flix.cli('imu') + + print('=== Check parameters') + assert isfinite(flix.get_param('CTL_ATT_P_P')) + flix.set_param('CTL_ATT_P_P', 10.0) + + print('=== Additional checks') + assert flix.wait('gyro') == approx((0, 0, 0), abs=0.01) + flix.wait('armed', False) + flix.wait('mode', 'STAB') + flix.wait('motors', lambda motors: not any(motors)) + flix.set_armed(True) + flix.wait('armed', True) + flix.set_mode('ACRO') + flix.wait('mode', 'ACRO') + flix.set_mode('AUTO') + flix.wait('mode', 'AUTO')