Merge pull request #370 from dpw13/fix/audit-strcpy #1074
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Integration Tests | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - 'feature/**' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| checks: write | |
| pull-requests: write | |
| jobs: | |
| unity-tests: | |
| name: Unity C Tests (Layer 1 + Layer 2) | |
| runs-on: ubuntu-latest | |
| container: debian:sid-slim | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Install C build dependencies | |
| run: | | |
| apt-get update | |
| apt-get install -y \ | |
| git \ | |
| build-essential \ | |
| cmake \ | |
| pkg-config \ | |
| libavcodec-dev \ | |
| libavformat-dev \ | |
| libavutil-dev \ | |
| libswscale-dev \ | |
| libsqlite3-dev \ | |
| libuv1-dev \ | |
| libllhttp-dev \ | |
| libcurl4-openssl-dev \ | |
| libcjson-dev \ | |
| libmbedtls-dev \ | |
| lcov \ | |
| curl \ | |
| gpg | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| submodules: false | |
| - name: Build Unity tests | |
| run: | | |
| mkdir -p build | |
| cd build | |
| cmake .. \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DBUILD_TESTS=ON \ | |
| -DENABLE_SOD=OFF \ | |
| -DENABLE_GO2RTC=OFF \ | |
| -DENABLE_MQTT=OFF \ | |
| -DCMAKE_C_FLAGS="--coverage" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="--coverage" | |
| make -j$(nproc) \ | |
| test_storage_pressure \ | |
| test_storage_pressure_extended \ | |
| test_detection_result_structures \ | |
| test_storage_retention_sqlite \ | |
| test_config \ | |
| test_logger \ | |
| test_strings \ | |
| test_memory \ | |
| test_request_response \ | |
| test_shutdown_coordinator \ | |
| test_detection_config \ | |
| test_detection_model_motion \ | |
| test_db_streams \ | |
| test_db_recordings_extended \ | |
| test_db_detections \ | |
| test_db_zones \ | |
| test_db_events \ | |
| test_db_auth \ | |
| test_db_transactions \ | |
| test_db_maintenance \ | |
| test_db_query_builder \ | |
| test_logger_json \ | |
| test_batch_delete_progress \ | |
| test_db_motion_config \ | |
| test_db_recordings_sync \ | |
| test_httpd_utils \ | |
| test_zone_filter \ | |
| test_onvif_soap_fault \ | |
| test_stream_manager \ | |
| test_stream_state \ | |
| test_packet_buffer \ | |
| test_timestamp_manager | |
| echo "Unity test binaries built:" | |
| ls -la bin/test_* | |
| - name: Run Unity tests | |
| run: | | |
| cd build | |
| ctest --output-on-failure -V \ | |
| -R "test_storage_pressure$|test_storage_pressure_extended|test_detection_result_structures|test_storage_retention_sqlite|test_config|test_logger|test_strings|test_memory|test_request_response|test_shutdown_coordinator|test_detection_config|test_detection_model_motion|test_db_streams|test_db_recordings_extended|test_db_detections|test_db_zones|test_db_events|test_db_auth|test_db_transactions|test_db_maintenance|test_db_query_builder|test_logger_json|test_batch_delete_progress|test_db_motion_config|test_db_recordings_sync|test_httpd_utils|test_zone_filter|test_onvif_soap_fault|test_stream_manager|test_stream_state|test_packet_buffer|test_timestamp_manager" | |
| - name: Generate coverage report | |
| if: always() | |
| run: | | |
| cd build | |
| # Collect coverage data from all .gcda files generated during the test run | |
| lcov --capture \ | |
| --directory . \ | |
| --output-file coverage.info \ | |
| --ignore-errors mismatch | |
| # Strip noise: system headers, third-party code, and the test files themselves | |
| lcov --remove coverage.info \ | |
| '/usr/*' \ | |
| '*/third_party/*' \ | |
| '*/external/*' \ | |
| '*/tests/*' \ | |
| --output-file coverage_filtered.info \ | |
| --ignore-errors unused | |
| # Print a quick per-file summary to the job log | |
| lcov --list coverage_filtered.info | |
| # Render HTML | |
| genhtml coverage_filtered.info \ | |
| --output-directory ../coverage-report \ | |
| --title "LightNVR C Unit-Test Coverage" \ | |
| --show-details \ | |
| --legend | |
| echo "Coverage report generated at coverage-report/" | |
| - name: Upload coverage report | |
| uses: actions/upload-artifact@v6 | |
| if: always() | |
| with: | |
| name: c-coverage-report | |
| path: coverage-report/ | |
| retention-days: 30 | |
| - name: Upload to Codecov | |
| uses: codecov/codecov-action@v5 | |
| if: always() | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: build/coverage_filtered.info | |
| flags: unity-c | |
| name: lightnvr-c-coverage | |
| fail_ci_if_error: false | |
| - name: Upload test results on failure | |
| uses: actions/upload-artifact@v6 | |
| if: failure() | |
| with: | |
| name: unity-test-results | |
| path: build/Testing/ | |
| retention-days: 7 | |
| playwright-tests: | |
| name: Playwright Integration Tests (Layer 3) | |
| needs: unity-tests | |
| runs-on: ubuntu-latest | |
| container: debian:sid-slim | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| apt-get update | |
| apt-get install -y \ | |
| git \ | |
| build-essential \ | |
| cmake \ | |
| pkg-config \ | |
| libavcodec-dev \ | |
| libavformat-dev \ | |
| libavutil-dev \ | |
| libswscale-dev \ | |
| libsqlite3-dev \ | |
| libuv1-dev \ | |
| libllhttp-dev \ | |
| libcurl4-openssl-dev \ | |
| libcjson-dev \ | |
| libmbedtls-dev \ | |
| ffmpeg \ | |
| curl \ | |
| jq \ | |
| golang-go \ | |
| nodejs \ | |
| npm \ | |
| procps | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| with: | |
| submodules: recursive | |
| - name: Build go2rtc from source | |
| run: | | |
| # Build go2rtc from the opensensor fork submodule | |
| cd go2rtc | |
| echo "Building go2rtc from source..." | |
| CGO_ENABLED=0 go build -buildvcs=false -ldflags "-s -w" -trimpath -o go2rtc | |
| chmod +x go2rtc | |
| ./go2rtc --version || echo "go2rtc built successfully" | |
| echo "go2rtc binary size: $(stat -c%s go2rtc) bytes" | |
| # Binary is now at go2rtc/go2rtc - exactly where lightnvr-test.ini expects it | |
| - name: Build lightNVR | |
| run: | | |
| mkdir -p build | |
| cd build | |
| cmake .. \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DENABLE_GO2RTC=ON \ | |
| -DGO2RTC_BINARY_PATH=$(pwd)/../go2rtc/go2rtc | |
| make -j$(nproc) | |
| echo "lightNVR built successfully" | |
| ls -la bin/lightnvr | |
| - name: Build web frontend | |
| run: | | |
| cd web | |
| npm ci | |
| npm run build | |
| echo "Web frontend built successfully" | |
| ls -la dist/ | head -10 | |
| - name: Install Playwright dependencies | |
| run: | | |
| npm ci | |
| npx playwright install --with-deps chromium | |
| - name: Run Playwright UI tests | |
| run: | | |
| # Clean any existing playwright reports to ensure fresh state | |
| rm -rf playwright-report test-results | |
| mkdir -p playwright-report test-results | |
| # Pre-flight checks before running tests | |
| echo "=== Pre-flight checks ===" | |
| echo "Checking if lightNVR binary exists..." | |
| ls -la build/bin/lightnvr || echo "lightNVR binary NOT found" | |
| echo "" | |
| echo "Checking if go2rtc binary exists..." | |
| ls -la go2rtc/go2rtc || echo "go2rtc binary NOT found" | |
| echo "" | |
| echo "Checking if web/dist exists..." | |
| ls -la web/dist/ | head -5 || echo "web/dist NOT found" | |
| echo "" | |
| echo "Checking if config file exists..." | |
| ls -la config/lightnvr-test.ini || echo "Config file NOT found" | |
| echo "" | |
| # Try to manually start lightNVR to see if it works | |
| echo "=== Attempting manual lightNVR start for diagnostics ===" | |
| mkdir -p /tmp/lightnvr-test/recordings /tmp/lightnvr-test/go2rtc | |
| timeout 10 ./build/bin/lightnvr -c config/lightnvr-test.ini & | |
| MANUAL_PID=$! | |
| echo "Started lightNVR manually with PID: $MANUAL_PID" | |
| sleep 5 | |
| # Check if it's still running | |
| if kill -0 $MANUAL_PID 2>/dev/null; then | |
| echo "lightNVR is running (PID: $MANUAL_PID)" | |
| # Check if it's listening on port 18080 | |
| if curl -s -u admin:admin http://localhost:18080/api/system > /dev/null 2>&1; then | |
| echo "lightNVR is responding on port 18080" | |
| else | |
| echo "lightNVR is NOT responding on port 18080" | |
| netstat -tlpn | grep 18080 || echo "Port 18080 is not listening" | |
| fi | |
| else | |
| echo "lightNVR process exited" | |
| wait $MANUAL_PID | |
| echo "Exit code: $?" | |
| fi | |
| # Check logs | |
| if [ -f /tmp/lightnvr-test/lightnvr.log ]; then | |
| echo "=== lightNVR log (last 50 lines) ===" | |
| tail -50 /tmp/lightnvr-test/lightnvr.log | |
| else | |
| echo "No log file at /tmp/lightnvr-test/lightnvr.log" | |
| fi | |
| # Kill the manual instance and ALL child processes it spawned | |
| # (lightNVR starts go2rtc as a child; killing only $MANUAL_PID leaves | |
| # go2rtc alive on port 11984, causing playwright's lightNVR to fail | |
| # with "Cannot start go2rtc because port 11984 is already in use") | |
| kill $MANUAL_PID 2>/dev/null || true | |
| pkill -TERM -f lightnvr 2>/dev/null || true | |
| pkill -TERM -f go2rtc 2>/dev/null || true | |
| sleep 3 | |
| pkill -KILL -f lightnvr 2>/dev/null || true | |
| pkill -KILL -f go2rtc 2>/dev/null || true | |
| sleep 1 | |
| # Clean up for actual test run | |
| rm -rf /tmp/lightnvr-test | |
| echo "" | |
| echo "=== Running Playwright tests ===" | |
| # Run Playwright tests with output capture. | |
| # Avoid ${PIPESTATUS[0]} — it is bash-only and the container | |
| # shell is /bin/sh (dash). Capture the exit code directly. | |
| RESULT=0 | |
| npx playwright test --project=ui > playwright-output.log 2>&1 || RESULT=$? | |
| cat playwright-output.log | |
| if [ $RESULT -ne 0 ]; then | |
| echo "" | |
| echo "=== Playwright tests failed ===" | |
| echo "" | |
| echo "Checking if lightNVR is still running..." | |
| pgrep -a lightnvr || echo "lightNVR is NOT running" | |
| pgrep -a go2rtc || echo "go2rtc is NOT running" | |
| echo "" | |
| echo "Checking lightNVR logs..." | |
| if [ -f /tmp/lightnvr-test/lightnvr.log ]; then | |
| echo "=== Last 200 lines of lightnvr.log ===" | |
| tail -200 /tmp/lightnvr-test/lightnvr.log | |
| else | |
| echo "No log file found at /tmp/lightnvr-test/lightnvr.log" | |
| fi | |
| echo "" | |
| echo "Checking for core dumps..." | |
| ls -la /tmp/core* 2>/dev/null || echo "No core dumps found" | |
| echo "" | |
| exit $RESULT | |
| fi | |
| env: | |
| CI: true | |
| - name: Upload Playwright report | |
| uses: actions/upload-artifact@v6 | |
| if: always() | |
| with: | |
| name: playwright-report | |
| path: playwright-report/ | |
| retention-days: 30 | |
| - name: Upload test screenshots | |
| uses: actions/upload-artifact@v6 | |
| if: failure() | |
| with: | |
| name: test-screenshots | |
| path: test-results/ | |
| retention-days: 7 | |
| - name: Upload lightNVR logs | |
| uses: actions/upload-artifact@v6 | |
| if: failure() | |
| with: | |
| name: lightnvr-logs | |
| path: | | |
| /tmp/lightnvr-test/ | |
| playwright-output.log | |
| retention-days: 7 | |
| - name: Cleanup | |
| if: always() | |
| run: | | |
| # Stop any remaining processes | |
| pkill -f lightnvr || true | |
| pkill -f go2rtc || true | |
| # Clean up test artifacts | |
| rm -rf /tmp/lightnvr-test | |