Skip to content

feat(dashboard): info button opens in-app modal instead of external b… #368

feat(dashboard): info button opens in-app modal instead of external b…

feat(dashboard): info button opens in-app modal instead of external b… #368

Workflow file for this run

name: Example Smoke Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 7 * * 1' # Weekly Monday 07:00 UTC — MATLAB examples
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-mex:
name: Build MEX
uses: ./.github/workflows/_build-mex-octave.yml
with:
artifact-name: mex-linux-examples
smoke-test:
name: Example Smoke Tests
timeout-minutes: 45
needs: build-mex
runs-on: ubuntu-latest
container: gnuoctave/octave:11.1.0
env:
FASTSENSE_SKIP_BUILD: "1"
steps:
- uses: actions/checkout@v6
- name: Download MEX binaries
uses: actions/download-artifact@v8
with:
name: mex-linux-examples
- name: Run example smoke tests
shell: bash
run: |
# Each example runs in its own Octave subprocess so that a segfault
# in one example (e.g. during close-all cleanup) does not kill the
# entire test suite.
EXAMPLES=(
# Core
example_basic
example_multi
example_datetime
example_nan_gaps
example_vibration
example_ecg
example_linked
example_uneven_sampling
example_alarm_bands
example_lttb_vs_minmax
example_multi_sensor_linked
example_navigator_overlay
example_visual_features
example_toolbar
example_100M
# Dashboard (basic grid — no DashboardEngine)
example_dashboard
example_dashboard_9tile
# Sensor
example_sensor_static
example_sensor_multi_state
example_sensor_threshold
example_sensor_registry
example_sensor_dashboard
# Heavy
example_dynamic_thresholds_100M
# -----------------------------------------------------------------
# Skipped — Octave-incompatible (MATLAB-only features):
# example_themes — segfault in Octave figure cleanup
# example_mixed_tiles — uses 'categorical' (MATLAB-only)
# example_dock — uses 'datetime' (MATLAB-only)
# example_dock_many_tabs — uses 'datetime'
# example_dock_disk — uses 'datetime'
# example_disk_storage — MATLAB-only API
# example_sensor_detail_* — 'disableDefaultInteractivity' / datetime
# example_sensor_todisk — MATLAB-only API
# example_stress_test — interactive / long-running
# Skipped — DashboardWidget uses abstract methods, Octave requires @-folders:
# example_dashboard_engine example_dashboard_all_widgets
# example_dashboard_groups example_dashboard_info
# example_dashboard_advanced example_widget_*
# Skipped — requires interaction / runs indefinitely:
# demo_all — input() call
# example_dashboard_live — live timer
# example_event_detection_live — live timer
# example_event_viewer_from_file — background timer
# example_live_pipeline — starts 15s timer
# example_sensor_detail — bare pause; calls
)
# Start a persistent Xvfb so individual runs don't race for displays
Xvfb :99 -screen 0 1280x1024x24 &
XVFB_PID=$!
export DISPLAY=:99
sleep 1
PASSED=0
FAILED=0
FAIL_LIST=""
TOTAL=${#EXAMPLES[@]}
for name in "${EXAMPLES[@]}"; do
printf "Running %s... " "$name"
if octave --eval "
addpath(pwd); install();
cd('examples');
$name();
close all force;
" > /tmp/example_out.log 2>&1; then
echo "OK"
PASSED=$((PASSED + 1))
else
EC=$?
echo "FAILED (exit code $EC)"
tail -40 /tmp/example_out.log | grep -v '^\s*$' | tail -15 | sed 's/^/ /'
FAILED=$((FAILED + 1))
FAIL_LIST="${FAIL_LIST}\n - ${name}"
fi
done
kill $XVFB_PID 2>/dev/null || true
echo ""
echo "=== ${PASSED}/${TOTAL} examples passed ==="
# --- GitHub Step Summary ---
if [ -n "$GITHUB_STEP_SUMMARY" ]; then
{
echo "### Octave Example Smoke Tests"
echo ""
echo "- ${PASSED:-0}/${TOTAL:-0} passed"
if [ -n "$FAIL_LIST" ]; then
echo ""
echo "**Failures:**"
echo ""
printf "%b" "$FAIL_LIST" | sed 's/^/- /'
fi
} >> "$GITHUB_STEP_SUMMARY"
fi
if [ "$FAILED" -gt 0 ]; then
echo ""
printf "Failed:%b\n" "$FAIL_LIST"
exit 1
fi
matlab-examples:
name: MATLAB Example Smoke Tests
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup MATLAB
uses: matlab-actions/setup-matlab@v3
with:
# Matches tests.yml (PR #109): R2020b libmex segfaults on the
# GitHub xvfb runner; codebase targets R2021a+ uifigure features.
release: R2021b
cache: true
- name: Run MATLAB-only examples
uses: matlab-actions/run-command@v3
with:
command: |
install();
cd('examples');
examples = {
% DashboardEngine examples (require abstract classdef — MATLAB only)
'example_dashboard_engine'
'example_dashboard_all_widgets'
'example_dashboard_groups'
'example_dashboard_info'
'example_dashboard_advanced'
% Individual widget examples
'example_widget_fastsense'
'example_widget_number'
'example_widget_status'
'example_widget_text'
'example_widget_gauge'
'example_widget_table'
'example_widget_rawaxes'
'example_widget_timeline'
'example_widget_group'
'example_widget_barchart'
'example_widget_heatmap'
'example_widget_histogram'
'example_widget_scatter'
'example_widget_image'
'example_widget_multistatus'
% Other MATLAB-only examples
'example_themes'
'example_mixed_tiles'
'example_dock'
'example_dock_many_tabs'
'example_sensor_detail_basic'
'example_sensor_detail_dashboard'
};
passed = 0;
failed = 0;
failList = {};
for i = 1:numel(examples)
name = examples{i};
fprintf('Running %s... ', name);
try
feval(name);
close all force;
fprintf('OK\n');
passed = passed + 1;
catch e
fprintf('FAILED\n %s\n', e.message);
failed = failed + 1;
failList{end+1} = name;
end
end
fprintf('\n=== %d/%d examples passed ===\n', passed, numel(examples));
nTotal = numel(examples);
nPassed = passed;
try
summaryFile = getenv('GITHUB_STEP_SUMMARY');
if ~isempty(summaryFile)
fid = fopen(summaryFile, 'a');
if fid > 0
fprintf(fid, '### MATLAB Examples\n\n');
fprintf(fid, '- %d/%d passed\n', nPassed, nTotal);
if nTotal - nPassed > 0 && ~isempty(failList)
fprintf(fid, '\n**Failures:**\n\n');
for k = 1:numel(failList)
fprintf(fid, '- %s\n', failList{k});
end
end
fclose(fid);
end
end
catch
% never fail the job because of a step-summary write
end
if failed > 0
fprintf('\nFailed:\n');
for i = 1:numel(failList)
fprintf(' - %s\n', failList{i});
end
error('ExampleSmokeTests:failed', '%d example(s) failed', failed);
end