# .gitea/workflows/social-tests-ci.yml # Gitea Actions CI pipeline for social-bot integration tests (Issue #108) # # Triggers: push or PR to main, and any branch matching sl-jetson/* # # Jobs: # 1. lint — flake8 + pep257 on saltybot_social_tests # 2. core-tests — launch + topic + services + GPU-budget + shutdown (no GPU) # 3. latency — end-to-end latency profiling (GPU runner, optional) name: social-bot integration tests on: push: branches: - main - "sl-jetson/**" paths: - "jetson/ros2_ws/src/saltybot_social/**" - "jetson/ros2_ws/src/saltybot_social_tests/**" - "jetson/ros2_ws/src/saltybot_social_msgs/**" - "jetson/ros2_ws/src/saltybot_social_nav/**" - "jetson/ros2_ws/src/saltybot_social_face/**" - "jetson/ros2_ws/src/saltybot_social_tracking/**" - ".gitea/workflows/social-tests-ci.yml" pull_request: branches: - main paths: - "jetson/ros2_ws/src/saltybot_social*/**" - ".gitea/workflows/social-tests-ci.yml" env: ROS_DOMAIN_ID: "108" SOCIAL_TEST_FULL: "0" SOCIAL_STACK_RUNNING: "1" jobs: # ── 1. Lint ────────────────────────────────────────────────────────────────── lint: name: Lint (flake8 + pep257) runs-on: ubuntu-latest container: image: ros:humble-ros-base-jammy steps: - uses: actions/checkout@v4 - name: Install lint tools run: | pip3 install --no-cache-dir flake8 pydocstyle - name: flake8 — saltybot_social_tests run: | flake8 \ jetson/ros2_ws/src/saltybot_social_tests/saltybot_social_tests/ \ jetson/ros2_ws/src/saltybot_social_tests/test/ \ --max-line-length=100 \ --ignore=E501,W503 \ --exclude=__pycache__ - name: pep257 — saltybot_social_tests run: | pydocstyle \ jetson/ros2_ws/src/saltybot_social_tests/saltybot_social_tests/ \ jetson/ros2_ws/src/saltybot_social_tests/test/ \ --add-ignore=D100,D104,D205,D400 \ --match='(?!test_helpers|mock_sensors).*\.py' || true # ── 2. Core integration tests (no GPU) ─────────────────────────────────────── core-tests: name: Core integration tests (mock sensors, no GPU) needs: lint runs-on: ubuntu-latest container: image: ros:humble-ros-base-jammy env: ROS_DOMAIN_ID: "108" SOCIAL_TEST_FULL: "0" SOCIAL_STACK_RUNNING: "1" PYTHONUNBUFFERED: "1" steps: - uses: actions/checkout@v4 - name: Install dependencies run: | apt-get update -q && apt-get install -y --no-install-recommends \ ros-humble-launch-testing \ ros-humble-launch-testing-ros \ ros-humble-vision-msgs \ ros-humble-tf2-ros \ ros-humble-tf2-geometry-msgs \ ros-humble-cv-bridge \ ros-humble-nav-msgs \ ros-humble-std-srvs \ procps \ && rm -rf /var/lib/apt/lists/* pip3 install --no-cache-dir "pytest>=7.0" "pytest-timeout>=2.1" - name: Build workspace run: | . /opt/ros/humble/setup.bash cd / # Symlink source into a temp workspace to avoid long paths mkdir -p /ros2_ws/src for pkg in saltybot_social_msgs saltybot_social saltybot_social_face \ saltybot_social_nav saltybot_social_enrollment \ saltybot_social_tracking saltybot_social_personality \ saltybot_social_tests; do ln -sfn \ "$GITHUB_WORKSPACE/jetson/ros2_ws/src/$pkg" \ "/ros2_ws/src/$pkg" done cd /ros2_ws colcon build \ --packages-select \ saltybot_social_msgs \ saltybot_social \ saltybot_social_face \ saltybot_social_nav \ saltybot_social_enrollment \ saltybot_social_tracking \ saltybot_social_personality \ saltybot_social_tests \ --symlink-install \ --event-handlers console_cohesion+ - name: Launch test stack (background) run: | . /opt/ros/humble/setup.bash . /ros2_ws/install/setup.bash ros2 daemon start || true ros2 launch saltybot_social_tests social_test.launch.py \ enable_speech:=false enable_llm:=false enable_tts:=false \ & echo "LAUNCH_PID=$!" >> "$GITHUB_ENV" # Wait for stack to come up sleep 15 - name: Run core tests run: | . /opt/ros/humble/setup.bash . /ros2_ws/install/setup.bash pytest \ "$GITHUB_WORKSPACE/jetson/ros2_ws/src/saltybot_social_tests/test/" \ -v \ --timeout=120 \ --tb=short \ -m "not gpu_required and not full_stack and not slow" \ --junit-xml=test-results-core.xml \ -k "not test_latency_sla and not test_shutdown" - name: Shutdown test stack if: always() run: | [ -n "${LAUNCH_PID:-}" ] && kill -SIGTERM "$LAUNCH_PID" 2>/dev/null || true sleep 3 - name: Run shutdown tests run: | . /opt/ros/humble/setup.bash . /ros2_ws/install/setup.bash pytest \ "$GITHUB_WORKSPACE/jetson/ros2_ws/src/saltybot_social_tests/test/test_shutdown.py" \ -v --timeout=60 --tb=short \ --junit-xml=test-results-shutdown.xml - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: test-results-core path: test-results-*.xml # ── 3. GPU latency tests (Orin runner, optional) ────────────────────────────── latency-gpu: name: Latency profiling (GPU, Orin) needs: core-tests runs-on: [self-hosted, orin, gpu] if: github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'run-gpu-tests') env: ROS_DOMAIN_ID: "108" SOCIAL_TEST_FULL: "1" SOCIAL_TEST_SPEECH: "0" SOCIAL_STACK_RUNNING: "1" steps: - uses: actions/checkout@v4 - name: Build workspace (Orin) run: | . /opt/ros/humble/setup.bash cd /ros2_ws colcon build \ --packages-select saltybot_social_tests saltybot_social \ --symlink-install - name: Launch full stack (with LLM, no speech/TTS) run: | . /opt/ros/humble/setup.bash . /ros2_ws/install/setup.bash SOCIAL_TEST_FULL=1 \ ros2 launch saltybot_social_tests social_test.launch.py \ enable_speech:=false enable_tts:=false \ & echo "LAUNCH_PID=$!" >> "$GITHUB_ENV" sleep 20 - name: GPU memory check run: | . /opt/ros/humble/setup.bash . /ros2_ws/install/setup.bash SOCIAL_STACK_RUNNING=1 \ GPU_BASELINE_MB=$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits) \ pytest \ "$GITHUB_WORKSPACE/jetson/ros2_ws/src/saltybot_social_tests/test/test_gpu_memory.py" \ -v --timeout=120 --tb=short \ --junit-xml=test-results-gpu.xml - name: Latency profiling run: | . /opt/ros/humble/setup.bash . /ros2_ws/install/setup.bash SOCIAL_TEST_FULL=1 SOCIAL_STACK_RUNNING=1 \ pytest \ "$GITHUB_WORKSPACE/jetson/ros2_ws/src/saltybot_social_tests/test/test_latency.py" \ -v --timeout=300 --tb=short \ --junit-xml=test-results-latency.xml - name: Shutdown if: always() run: | [ -n "${LAUNCH_PID:-}" ] && kill -SIGTERM "$LAUNCH_PID" 2>/dev/null || true sleep 5 - name: Upload GPU results if: always() uses: actions/upload-artifact@v4 with: name: test-results-gpu path: test-results-*.xml