Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/oss-integration.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
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
env:
PREFER_LLVM: 19
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
1 change: 1 addition & 0 deletions cmake/config_common.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 7 additions & 0 deletions cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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
#
Expand Down
128 changes: 128 additions & 0 deletions scripts/crash_handler_integration.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/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/flutter-samples/material_3_demo"
BUNDLE_DIR="${SAMPLES_DIR}/.desktop-homescreen"

KENT_PID=""

cleanup() {
if [[ -n "${KENT_PID}" ]]; then
kill "${KENT_PID}" 2>/dev/null || true
fi
}
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}" \
-D BUILD_BACKEND_WAYLAND_EGL=OFF \
-D BUILD_BACKEND_WAYLAND_VULKAN=OFF \
-D BUILD_BACKEND_DRM_KMS_EGL=OFF \
-D BUILD_BACKEND_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_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
return 1
fi

_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
2 changes: 2 additions & 0 deletions shell/crash_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

#include "sentry.h"

#if INTEGRATION_TEST_CRASH_HANDLER
volatile auto invalid_mem = reinterpret_cast<void*>(1);

void CrashHandler::trigger_crash() {
memset(invalid_mem, 1, 100);
}
#endif

CrashHandler::SentryConfig CrashHandler::LoadConfig(
const std::string& config_path) {
Expand Down
5 changes: 4 additions & 1 deletion shell/crash_handler.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#pragma once

#include <config/common.h>

#include <map>
#include <string>
#include <vector>
#include "sentry.h"

class CrashHandler {
public:
Expand All @@ -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;
Expand Down
17 changes: 17 additions & 0 deletions shell/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,23 @@ int main(const int argc, char** argv) {
auto crash_handler = std::make_unique<CrashHandler>(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[=<path>] 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
Expand Down
Loading