From b403e885b5bfaf3bb0579c812bbf6fb47d99c7f2 Mon Sep 17 00:00:00 2001 From: Jamie Kerber Date: Wed, 8 Jul 2026 15:22:32 +0200 Subject: [PATCH 1/3] Implemented Sentry integration test Implemented CI for integration testing Added crash handler integration builds script --- .github/workflows/oss-integration.yaml | 45 +++++++++++++ cmake/config_common.h.in | 1 + cmake/options.cmake | 7 ++ scripts/crash_handler_integration.sh | 89 ++++++++++++++++++++++++++ shell/crash_handler.cc | 2 + shell/crash_handler.h | 5 +- shell/main.cc | 17 +++++ 7 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/oss-integration.yaml create mode 100755 scripts/crash_handler_integration.sh diff --git a/.github/workflows/oss-integration.yaml b/.github/workflows/oss-integration.yaml new file mode 100644 index 000000000..28c64647a --- /dev/null +++ b/.github/workflows/oss-integration.yaml @@ -0,0 +1,45 @@ +--- +name: integration-test +description: Run integration test for ivi-homescreen + +on: + pull_request: + types: [opened, synchronize, reopened] + workflow_dispatch: + +jobs: + # Runs integration test for the CrashHandler (Sentry integration) + # - Sets up a local Kent (fake Sentry) server + # - Builds a homescreen binary with the crash handler and integration test enabled + # - Runs the binary, which intentionally crashes; checks if the crash report is received + crash-handler: + if: ${{ github.server_url == 'https://github.com' && github.ref != 'refs/heads/agl' }} + runs-on: ubuntu-22.04 + steps: + - name: Check Environment + id: check_environment + shell: bash + run: | + echo "Running on Ubuntu version: $(lsb_release -d | cut -f2)" + echo "Running on architecture: $(uname -m)" + echo "Current directory: $(pwd)" + echo "user=$(whoami)" >> "$GITHUB_OUTPUT" + + - name: Setup workspace + uses: meta-flutter/workspace-automation/.github/actions/setup-workspace@v2.0 + with: + args: --disable=rive-text --enable=sentry-native --override-repo=https://github.com/toyota-connected/ivi-homescreen.git#${{ github.event.pull_request.head.ref && format('heads/{0}', github.event.pull_request.head.ref) || github.sha }} + user: ${{ steps.check_environment.outputs.user }} + ref: v2.0 + cache: false + cache-key: crash-handler-integration-pr${{ github.event.pull_request.number }} + + - name: Run integration test for crash handler + shell: bash + run: | + cd "${{ github.workspace }}" + source ./setup_env.sh + cd ./app/ivi-homescreen + ls -al scripts + git status + ./scripts/crash_handler_integration.sh diff --git a/cmake/config_common.h.in b/cmake/config_common.h.in index 1b5d2de12..107fc3137 100644 --- a/cmake/config_common.h.in +++ b/cmake/config_common.h.in @@ -74,6 +74,7 @@ static constexpr char kSentryEnvDefault[] = "@CMAKE_BUILD_TYPE@"; static constexpr char kCrashpadBinaryPath[] = "@CRASHPAD_BINARY_DIR@/crashpad_handler"; #endif +#cmakedefine01 INTEGRATION_TEST_CRASH_HANDLER #cmakedefine01 BUILD_ACCESSIBILITY diff --git a/cmake/options.cmake b/cmake/options.cmake index 488a90ecc..e85fc3fc0 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -248,6 +248,13 @@ else() message(STATUS "Crash Handler .......... Disabled") endif () +option(INTEGRATION_TEST_CRASH_HANDLER "Enable crash handler integration test" OFF) +if (INTEGRATION_TEST_CRASH_HANDLER) + message(STATUS "Crash Handler Integration Test ... Enabled") +else() + message(STATUS "Crash Handler Integration Test ... Disabled") +endif () + # # watchdog # diff --git a/scripts/crash_handler_integration.sh b/scripts/crash_handler_integration.sh new file mode 100755 index 000000000..9ad662d1e --- /dev/null +++ b/scripts/crash_handler_integration.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Crash-handler integration test — mirrors the crash-handler job in +# .github/workflows/oss-integration.yaml for local / Docker reproduction. +# +# Intended to be run inside a Docker container via: +# /home/jamie/workspace-automation/run-docker.sh ubuntu:22.04 amd64 \ +# "scripts/crash_handler_integration.sh" +# +# Prerequisites (handled by flutter_workspace.py before this script runs): +# - sentry-native built under ${FLUTTER_WORKSPACE}/app/sentry-native/ +# - ivi-homescreen sources at ${FLUTTER_WORKSPACE}/app/ivi-homescreen/ +# - material_3_demo at ${FLUTTER_WORKSPACE}/app/samples/material_3_demo/ +# +# Environment variables (all optional): +# KENT_HOST — host for the fake Sentry server (default: 127.0.0.1) +# KENT_PORT — port for the fake Sentry server (default: 5000) + +set -euo pipefail + +KENT_HOST="${KENT_HOST:-127.0.0.1}" +KENT_PORT="${KENT_PORT:-5000}" + +IVI_SRC="${FLUTTER_WORKSPACE}/app/ivi-homescreen" +IVI_BUILD="${IVI_SRC}/build" +SENTRY_LIBDIR="${FLUTTER_WORKSPACE}/app/sentry-native/build/release/staging" +CRASHPAD_BINDIR="${FLUTTER_WORKSPACE}/app/sentry-native/build/release/crashpad_build/handler" +SAMPLES_DIR="${FLUTTER_WORKSPACE}/app/samples/material_3_demo" + +KENT_PID="" + +cleanup() { + if [[ -n "${KENT_PID}" ]]; then + kill "${KENT_PID}" 2>/dev/null || true + fi +} +trap cleanup EXIT + +# --------------------------------------------------------------------------- +# Configure +# --------------------------------------------------------------------------- +cmake \ + -S "${IVI_SRC}" \ + -B "${IVI_BUILD}" \ + -D BUILD_BACKEND_WAYLAND_EGL=OFF \ + -D BUILD_BACKEND_WAYLAND_VULKAN=OFF \ + -D BUILD_BACKEND_HEADLESS_SOFTWARE=ON \ + -D BUILD_CRASH_HANDLER=ON \ + -D INTEGRATION_TEST_CRASH_HANDLER=ON + +# --------------------------------------------------------------------------- +# Build +# --------------------------------------------------------------------------- +ninja -C "${IVI_BUILD}" + +# --------------------------------------------------------------------------- +# Install and start Kent (fake Sentry server) +# --------------------------------------------------------------------------- +pip install kent + +kent-server run --host "${KENT_HOST}" --port "${KENT_PORT}" & +KENT_PID=$! +sleep 2 + +# --------------------------------------------------------------------------- +# Run homescreen (expected to crash) +# --------------------------------------------------------------------------- +set +e +SENTRY_DSN="http://public@${KENT_HOST}:${KENT_PORT}/1" \ + "${IVI_BUILD}/shell/homescreen" -b "${SAMPLES_DIR}" +HOMESCREEN_EXIT_CODE=$? +set -e + +if [[ "${HOMESCREEN_EXIT_CODE}" == "0" ]]; then + echo "error: homescreen exited with 0 — expected a crash (non-zero exit)" >&2 +fi +echo "homescreen exited with code ${HOMESCREEN_EXIT_CODE} as expected" + +# --------------------------------------------------------------------------- +# Wait for crash report delivery, then verify Kent received it +# --------------------------------------------------------------------------- +sleep 10 + +response=$(curl -sf "http://${KENT_HOST}:${KENT_PORT}/api/eventlist/") +echo "Kent event list: ${response}" +if [[ "${response}" == "[]" || -z "${response}" ]]; then + echo "error: Kent received no crash reports — sentry-native did not submit the crash" >&2 + exit 1 +fi +echo "Crash report successfully received by Kent" diff --git a/shell/crash_handler.cc b/shell/crash_handler.cc index 8bdb3f4c5..8c87ea9bf 100644 --- a/shell/crash_handler.cc +++ b/shell/crash_handler.cc @@ -12,11 +12,13 @@ #include "sentry.h" +#if INTEGRATION_TEST_CRASH_HANDLER volatile auto invalid_mem = reinterpret_cast(1); void CrashHandler::trigger_crash() { memset(invalid_mem, 1, 100); } +#endif CrashHandler::SentryConfig CrashHandler::LoadConfig( const std::string& config_path) { diff --git a/shell/crash_handler.h b/shell/crash_handler.h index ab6b42598..32e064a53 100644 --- a/shell/crash_handler.h +++ b/shell/crash_handler.h @@ -1,9 +1,10 @@ #pragma once +#include + #include #include #include -#include "sentry.h" class CrashHandler { public: @@ -14,7 +15,9 @@ class CrashHandler { ~CrashHandler(); +#if INTEGRATION_TEST_CRASH_HANDLER static void trigger_crash(); +#endif CrashHandler(const CrashHandler&) = delete; CrashHandler& operator=(const CrashHandler&) = delete; diff --git a/shell/main.cc b/shell/main.cc index b50705dc7..4530e2070 100644 --- a/shell/main.cc +++ b/shell/main.cc @@ -93,6 +93,23 @@ int main(const int argc, char** argv) { auto crash_handler = std::make_unique(sentry_config_path); #endif +#if INTEGRATION_TEST_CRASH_HANDLER + // If we're running the crash handler integration test, trigger a crash and + // exit immediately. The test runner will then check if the crash was captured + // successfully. + + spdlog::info( + "Running crash handler integration test: triggering crash in 3 " + "seconds..."); + std::this_thread::sleep_for(std::chrono::seconds(3)); + + CrashHandler::trigger_crash(); + spdlog::error( + "Crash handler integration test failed: trigger_crash() returned instead " + "of crashing."); + return 231; +#endif + // Handle --drm-list-modes[=] as an early exit so the user doesn't need // to supply a bundle just to inspect modes. It is dispatched to the active // backend's mode lister (DRM lists the scanout connector's modes; software From ebe79070d8dc18ecd644f7d2cfb99e886d1903c6 Mon Sep 17 00:00:00 2001 From: Jamie Kerber Date: Fri, 26 Jun 2026 02:34:50 +0200 Subject: [PATCH 2/3] Rewire integration test for valid runtime configuration --- .github/workflows/oss-integration.yaml | 2 + scripts/crash_handler_integration.sh | 88 ++++++++++++++++++-------- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/.github/workflows/oss-integration.yaml b/.github/workflows/oss-integration.yaml index 28c64647a..e6dbb5fec 100644 --- a/.github/workflows/oss-integration.yaml +++ b/.github/workflows/oss-integration.yaml @@ -15,6 +15,8 @@ jobs: crash-handler: if: ${{ github.server_url == 'https://github.com' && github.ref != 'refs/heads/agl' }} runs-on: ubuntu-22.04 + env: + PREFER_LLVM: 19 steps: - name: Check Environment id: check_environment diff --git a/scripts/crash_handler_integration.sh b/scripts/crash_handler_integration.sh index 9ad662d1e..75f61e7e4 100755 --- a/scripts/crash_handler_integration.sh +++ b/scripts/crash_handler_integration.sh @@ -24,7 +24,8 @@ IVI_SRC="${FLUTTER_WORKSPACE}/app/ivi-homescreen" IVI_BUILD="${IVI_SRC}/build" SENTRY_LIBDIR="${FLUTTER_WORKSPACE}/app/sentry-native/build/release/staging" CRASHPAD_BINDIR="${FLUTTER_WORKSPACE}/app/sentry-native/build/release/crashpad_build/handler" -SAMPLES_DIR="${FLUTTER_WORKSPACE}/app/samples/material_3_demo" +SAMPLES_DIR="${FLUTTER_WORKSPACE}/app/flutter-samples/material_3_demo" +BUNDLE_DIR="${SAMPLES_DIR}/.desktop-homescreen" KENT_PID="" @@ -35,9 +36,22 @@ cleanup() { } trap cleanup EXIT +_dir=$(pwd) + +# --------------------------------------------------------------------------- +# Prepare test app +# --------------------------------------------------------------------------- +cd "${SAMPLES_DIR}" +# this is required to make sure a `.desktop-homescreen` bundle is generated +flutter pub get +flutter build bundle +flutter install -d desktop-homescreen +cd "${_dir}" + # --------------------------------------------------------------------------- # Configure # --------------------------------------------------------------------------- + cmake \ -S "${IVI_SRC}" \ -B "${IVI_BUILD}" \ @@ -61,29 +75,53 @@ kent-server run --host "${KENT_HOST}" --port "${KENT_PORT}" & KENT_PID=$! sleep 2 -# --------------------------------------------------------------------------- -# Run homescreen (expected to crash) -# --------------------------------------------------------------------------- -set +e -SENTRY_DSN="http://public@${KENT_HOST}:${KENT_PORT}/1" \ - "${IVI_BUILD}/shell/homescreen" -b "${SAMPLES_DIR}" -HOMESCREEN_EXIT_CODE=$? -set -e +run_and_verify_crash() { + # --------------------------------------------------------------------------- + # Run homescreen (expected to crash) + # --------------------------------------------------------------------------- + set +e + SENTRY_DSN="http://public@${KENT_HOST}:${KENT_PORT}/1" \ + "${IVI_BUILD}/shell/homescreen" -b "${BUNDLE_DIR}" + HOMESCREEN_EXIT_CODE=$? + set -e -if [[ "${HOMESCREEN_EXIT_CODE}" == "0" ]]; then - echo "error: homescreen exited with 0 — expected a crash (non-zero exit)" >&2 -fi -echo "homescreen exited with code ${HOMESCREEN_EXIT_CODE} as expected" + if [[ "${HOMESCREEN_EXIT_CODE}" == "0" ]]; then + echo "error: homescreen exited with 0 — expected a crash (non-zero exit)" >&2 + return 1 + fi -# --------------------------------------------------------------------------- -# Wait for crash report delivery, then verify Kent received it -# --------------------------------------------------------------------------- -sleep 10 - -response=$(curl -sf "http://${KENT_HOST}:${KENT_PORT}/api/eventlist/") -echo "Kent event list: ${response}" -if [[ "${response}" == "[]" || -z "${response}" ]]; then - echo "error: Kent received no crash reports — sentry-native did not submit the crash" >&2 - exit 1 -fi -echo "Crash report successfully received by Kent" + _expected_exit_code=139 + if [[ "${HOMESCREEN_EXIT_CODE}" != "${_expected_exit_code}" ]]; then + echo "error: homescreen exited with ${HOMESCREEN_EXIT_CODE} — expected ${_expected_exit_code}" >&2 + return 1 + else + echo "homescreen exited with expected crash code ${_expected_exit_code}" + fi + + # --------------------------------------------------------------------------- + # Wait for crash report delivery, then verify Kent received it + # --------------------------------------------------------------------------- + sleep 10 + + response=$(curl -sf "http://${KENT_HOST}:${KENT_PORT}/api/eventlist/") + echo "Kent event list: ${response}" + # response = { "events" : [ { "event_id" : "..." }, ... ] } + # use jq to get length of events array + event_count=$(echo "${response}" | jq '.events | length' || echo "0") + if [[ "${event_count}" == "0" ]]; then + echo "error: no crash reports received by Kent" >&2 + return 1 + fi + echo "Kent received ${event_count} crash report(s) as expected" +} + +for attempt in 1 2; do + if run_and_verify_crash; then + break + fi + if [[ "${attempt}" == "2" ]]; then + echo "error: crash handler verification failed after ${attempt} attempts" >&2 + exit 1 + fi + echo "Attempt ${attempt} failed, retrying..." +done \ No newline at end of file From 102b83641cf209a2706dcba363d06fac2c5ee678 Mon Sep 17 00:00:00 2001 From: Jamie Kerber Date: Wed, 8 Jul 2026 15:27:49 +0200 Subject: [PATCH 3/3] Updated to use Software backend + `NoneSink` --- scripts/crash_handler_integration.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/crash_handler_integration.sh b/scripts/crash_handler_integration.sh index 75f61e7e4..8d36f9078 100755 --- a/scripts/crash_handler_integration.sh +++ b/scripts/crash_handler_integration.sh @@ -57,7 +57,8 @@ cmake \ -B "${IVI_BUILD}" \ -D BUILD_BACKEND_WAYLAND_EGL=OFF \ -D BUILD_BACKEND_WAYLAND_VULKAN=OFF \ - -D BUILD_BACKEND_HEADLESS_SOFTWARE=ON \ + -D BUILD_BACKEND_DRM_KMS_EGL=OFF \ + -D BUILD_BACKEND_SOFTWARE=ON \ -D BUILD_CRASH_HANDLER=ON \ -D INTEGRATION_TEST_CRASH_HANDLER=ON