From df684d0c8dc7d304c71c54f8775b510a45af0a12 Mon Sep 17 00:00:00 2001 From: Alan George Date: Wed, 8 Apr 2026 22:02:22 -0600 Subject: [PATCH 01/11] First pass at unit tests in CI --- .github/workflows/builds.yml | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 1a7dfef..cf32bc6 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -53,22 +53,30 @@ jobs: name: linux-x64 build_cmd: ./build.sh release-examples build_dir: build-release + test_build_cmd: ./build.sh release-tests + run_tests: true - os: ubuntu-24.04-arm name: linux-arm64 build_cmd: ./build.sh release-examples build_dir: build-release + run_tests: false - os: macos-latest name: macos-arm64 build_cmd: ./build.sh release-examples build_dir: build-release + test_build_cmd: ./build.sh release-tests + run_tests: true - os: macos-latest name: macos-x64 build_cmd: ./build.sh release-examples --macos-arch x86_64 build_dir: build-release + run_tests: false - os: windows-latest name: windows-x64 build_cmd: .\build.cmd release-examples build_dir: build-release + test_build_cmd: .\build.cmd release-tests + run_tests: true name: Build (${{ matrix.name }}) runs-on: ${{ matrix.os }} @@ -233,6 +241,43 @@ jobs: } if ($failed) { exit 1 } else { exit 0 } + # ---------- Build and run integration tests ---------- + - name: Build tests (Unix) + if: runner.os != 'Windows' && matrix.run_tests + shell: bash + run: | + chmod +x build.sh + ${{ matrix.test_build_cmd }} + + - name: Build tests (Windows) + if: runner.os == 'Windows' && matrix.run_tests + shell: pwsh + run: ${{ matrix.test_build_cmd }} + + - name: Run integration tests (Unix) + if: runner.os != 'Windows' && matrix.run_tests + shell: bash + working-directory: ${{ matrix.build_dir }} + run: | + ctest --label-regex integration --output-on-failure --timeout 120 \ + --output-junit test-results.xml + + - name: Run integration tests (Windows) + if: runner.os == 'Windows' && matrix.run_tests + shell: pwsh + working-directory: ${{ matrix.build_dir }} + run: | + ctest --label-regex integration --output-on-failure --timeout 120 ` + --output-junit test-results.xml + + - name: Upload test results + if: always() && matrix.run_tests + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ matrix.name }} + path: ${{ matrix.build_dir }}/test-results.xml + retention-days: 7 + # ---------- Upload artifacts ---------- - name: Upload build artifacts uses: actions/upload-artifact@v4 From a931038681b15e7b00d30cc7ae96fb08909a1e0b Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 09:09:09 -0600 Subject: [PATCH 02/11] Separate unit tests --- .github/workflows/builds.yml | 34 ++++++--- src/tests/CMakeLists.txt | 74 +++++++++++++++++++ .../test_audio_frame.cpp | 0 3 files changed, 98 insertions(+), 10 deletions(-) rename src/tests/{integration => unit}/test_audio_frame.cpp (100%) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index cf32bc6..8498cc9 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -59,7 +59,7 @@ jobs: name: linux-arm64 build_cmd: ./build.sh release-examples build_dir: build-release - run_tests: false + run_tests: true - os: macos-latest name: macos-arm64 build_cmd: ./build.sh release-examples @@ -70,7 +70,7 @@ jobs: name: macos-x64 build_cmd: ./build.sh release-examples --macos-arch x86_64 build_dir: build-release - run_tests: false + run_tests: true - os: windows-latest name: windows-x64 build_cmd: .\build.cmd release-examples @@ -241,7 +241,7 @@ jobs: } if ($failed) { exit 1 } else { exit 0 } - # ---------- Build and run integration tests ---------- + # ---------- Build and run tests ---------- - name: Build tests (Unix) if: runner.os != 'Windows' && matrix.run_tests shell: bash @@ -254,28 +254,42 @@ jobs: shell: pwsh run: ${{ matrix.test_build_cmd }} + - name: Run unit tests (Unix) + if: runner.os != 'Windows' && matrix.run_tests + shell: bash + run: | + ${{ matrix.build_dir }}/bin/livekit_unit_tests \ + --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml + + - name: Run unit tests (Windows) + if: runner.os == 'Windows' && matrix.run_tests + shell: pwsh + run: | + & "${{ matrix.build_dir }}/bin/livekit_unit_tests.exe" ` + --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml + - name: Run integration tests (Unix) if: runner.os != 'Windows' && matrix.run_tests shell: bash - working-directory: ${{ matrix.build_dir }} run: | - ctest --label-regex integration --output-on-failure --timeout 120 \ - --output-junit test-results.xml + ${{ matrix.build_dir }}/bin/livekit_integration_tests \ + --gtest_output=xml:${{ matrix.build_dir }}/integration-test-results.xml - name: Run integration tests (Windows) if: runner.os == 'Windows' && matrix.run_tests shell: pwsh - working-directory: ${{ matrix.build_dir }} run: | - ctest --label-regex integration --output-on-failure --timeout 120 ` - --output-junit test-results.xml + & "${{ matrix.build_dir }}/bin/livekit_integration_tests.exe" ` + --gtest_output=xml:${{ matrix.build_dir }}/integration-test-results.xml - name: Upload test results if: always() && matrix.run_tests uses: actions/upload-artifact@v4 with: name: test-results-${{ matrix.name }} - path: ${{ matrix.build_dir }}/test-results.xml + path: | + ${{ matrix.build_dir }}/unit-test-results.xml + ${{ matrix.build_dir }}/integration-test-results.xml retention-days: 7 # ---------- Upload artifacts ---------- diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 1ca804d..bbea2b6 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -24,6 +24,76 @@ FetchContent_MakeAvailable(googletest) enable_testing() include(GoogleTest) +# ============================================================================ +# Unit Tests +# ============================================================================ + +file(GLOB UNIT_TEST_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/unit/*.cpp" +) + +if(UNIT_TEST_SOURCES) + add_executable(livekit_unit_tests + ${UNIT_TEST_SOURCES} + ) + + target_link_libraries(livekit_unit_tests + PRIVATE + livekit + GTest::gtest_main + GTest::gmock + ) + + target_include_directories(livekit_unit_tests + PRIVATE + ${LIVEKIT_ROOT_DIR}/include + ${LIVEKIT_ROOT_DIR}/src + ) + + target_compile_definitions(livekit_unit_tests + PRIVATE + LIVEKIT_TEST_ACCESS + ) + + if(WIN32) + add_custom_command(TARGET livekit_unit_tests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "$/livekit_ffi.dll" + $ + COMMENT "Copying DLLs to unit test directory" + ) + elseif(APPLE) + add_custom_command(TARGET livekit_unit_tests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "$/liblivekit_ffi.dylib" + $ + COMMENT "Copying dylibs to unit test directory" + ) + else() + add_custom_command(TARGET livekit_unit_tests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "$/liblivekit_ffi.so" + $ + COMMENT "Copying shared libraries to unit test directory" + ) + endif() + + gtest_discover_tests(livekit_unit_tests + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + PROPERTIES + LABELS "unit" + ) +endif() + # ============================================================================ # Integration Tests # ============================================================================ @@ -189,6 +259,10 @@ add_custom_target(run_all_tests COMMENT "Running all tests" ) +if(TARGET livekit_unit_tests) + add_dependencies(run_all_tests livekit_unit_tests) +endif() + if(TARGET livekit_integration_tests) add_dependencies(run_all_tests livekit_integration_tests) endif() diff --git a/src/tests/integration/test_audio_frame.cpp b/src/tests/unit/test_audio_frame.cpp similarity index 100% rename from src/tests/integration/test_audio_frame.cpp rename to src/tests/unit/test_audio_frame.cpp From 21bab19a453b5650d76a3e196b0a400bc708b88c Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 09:35:17 -0600 Subject: [PATCH 03/11] Fix unit tests on all platforms --- .github/workflows/builds.yml | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 8498cc9..b827a3e 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -59,6 +59,7 @@ jobs: name: linux-arm64 build_cmd: ./build.sh release-examples build_dir: build-release + test_build_cmd: ./build.sh release-tests run_tests: true - os: macos-latest name: macos-arm64 @@ -70,6 +71,7 @@ jobs: name: macos-x64 build_cmd: ./build.sh release-examples --macos-arch x86_64 build_dir: build-release + test_build_cmd: ./build.sh release-tests --macos-arch x86_64 run_tests: true - os: windows-latest name: windows-x64 @@ -268,20 +270,6 @@ jobs: & "${{ matrix.build_dir }}/bin/livekit_unit_tests.exe" ` --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml - - name: Run integration tests (Unix) - if: runner.os != 'Windows' && matrix.run_tests - shell: bash - run: | - ${{ matrix.build_dir }}/bin/livekit_integration_tests \ - --gtest_output=xml:${{ matrix.build_dir }}/integration-test-results.xml - - - name: Run integration tests (Windows) - if: runner.os == 'Windows' && matrix.run_tests - shell: pwsh - run: | - & "${{ matrix.build_dir }}/bin/livekit_integration_tests.exe" ` - --gtest_output=xml:${{ matrix.build_dir }}/integration-test-results.xml - - name: Upload test results if: always() && matrix.run_tests uses: actions/upload-artifact@v4 @@ -289,7 +277,6 @@ jobs: name: test-results-${{ matrix.name }} path: | ${{ matrix.build_dir }}/unit-test-results.xml - ${{ matrix.build_dir }}/integration-test-results.xml retention-days: 7 # ---------- Upload artifacts ---------- From 5911b652b991fd6ed7f26c05cc92129bd5b529ae Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 12:28:59 -0600 Subject: [PATCH 04/11] Move all gtest discovery to "PRE_TEST" preventing invocation automatically --- bridge/tests/CMakeLists.txt | 1 + src/tests/CMakeLists.txt | 3 +++ 2 files changed, 4 insertions(+) diff --git a/bridge/tests/CMakeLists.txt b/bridge/tests/CMakeLists.txt index c42274b..227f0a0 100644 --- a/bridge/tests/CMakeLists.txt +++ b/bridge/tests/CMakeLists.txt @@ -93,6 +93,7 @@ if(BRIDGE_TEST_SOURCES) # Register tests with CTest gtest_discover_tests(livekit_bridge_tests WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + DISCOVERY_MODE PRE_TEST PROPERTIES LABELS "bridge_unit" ) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index bbea2b6..2f32e70 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -89,6 +89,7 @@ if(UNIT_TEST_SOURCES) gtest_discover_tests(livekit_unit_tests WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + DISCOVERY_MODE PRE_TEST PROPERTIES LABELS "unit" ) @@ -175,6 +176,7 @@ if(INTEGRATION_TEST_SOURCES) # Register tests with CTest gtest_discover_tests(livekit_integration_tests WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + DISCOVERY_MODE PRE_TEST PROPERTIES LABELS "integration" ) @@ -243,6 +245,7 @@ if(STRESS_TEST_SOURCES) # Register tests with CTest (longer timeout for stress tests) gtest_discover_tests(livekit_stress_tests WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} + DISCOVERY_MODE PRE_TEST PROPERTIES LABELS "stress" TIMEOUT 300 From 57168898a1852a334e8891addcd85f9c11389395 Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 14:59:12 -0600 Subject: [PATCH 05/11] Try fixing test stages --- .github/workflows/builds.yml | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index b827a3e..9af3068 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -53,31 +53,32 @@ jobs: name: linux-x64 build_cmd: ./build.sh release-examples build_dir: build-release - test_build_cmd: ./build.sh release-tests + test_preset: linux-release-tests run_tests: true - os: ubuntu-24.04-arm name: linux-arm64 build_cmd: ./build.sh release-examples build_dir: build-release - test_build_cmd: ./build.sh release-tests + test_preset: linux-release-tests run_tests: true - os: macos-latest name: macos-arm64 build_cmd: ./build.sh release-examples build_dir: build-release - test_build_cmd: ./build.sh release-tests + test_preset: macos-release-tests run_tests: true - os: macos-latest name: macos-x64 build_cmd: ./build.sh release-examples --macos-arch x86_64 build_dir: build-release - test_build_cmd: ./build.sh release-tests --macos-arch x86_64 + test_preset: macos-release-tests + test_cmake_args: -DCMAKE_OSX_ARCHITECTURES=x86_64 run_tests: true - os: windows-latest name: windows-x64 build_cmd: .\build.cmd release-examples build_dir: build-release - test_build_cmd: .\build.cmd release-tests + test_preset: windows-release-tests run_tests: true name: Build (${{ matrix.name }}) @@ -244,17 +245,13 @@ jobs: if ($failed) { exit 1 } else { exit 0 } # ---------- Build and run tests ---------- - - name: Build tests (Unix) - if: runner.os != 'Windows' && matrix.run_tests - shell: bash - run: | - chmod +x build.sh - ${{ matrix.test_build_cmd }} + - name: Configure tests + if: matrix.run_tests + run: cmake --preset ${{ matrix.test_preset }} ${{ matrix.test_cmake_args }} - - name: Build tests (Windows) - if: runner.os == 'Windows' && matrix.run_tests - shell: pwsh - run: ${{ matrix.test_build_cmd }} + - name: Build unit tests + if: matrix.run_tests + run: cmake --build ${{ matrix.build_dir }} --config Release --target livekit_unit_tests - name: Run unit tests (Unix) if: runner.os != 'Windows' && matrix.run_tests From abbdba42ec288d4e64801a7634f92fe6a4aa1a7f Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 16:30:00 -0600 Subject: [PATCH 06/11] Move unit tests to unit folder --- src/tests/CMakeLists.txt | 13 +++++++++++++ .../test_audio_processing_module.cpp | 1 + src/tests/{integration => unit}/test_logging.cpp | 0 .../{integration => unit}/test_room_callbacks.cpp | 0 .../test_sdk_initialization.cpp | 0 .../test_subscription_thread_dispatcher.cpp | 0 6 files changed, 14 insertions(+) rename src/tests/{integration => unit}/test_audio_processing_module.cpp (99%) rename src/tests/{integration => unit}/test_logging.cpp (100%) rename src/tests/{integration => unit}/test_room_callbacks.cpp (100%) rename src/tests/{integration => unit}/test_sdk_initialization.cpp (100%) rename src/tests/{integration => unit}/test_subscription_thread_dispatcher.cpp (100%) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 2f32e70..02d942c 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -40,6 +40,7 @@ if(UNIT_TEST_SOURCES) target_link_libraries(livekit_unit_tests PRIVATE livekit + spdlog::spdlog GTest::gtest_main GTest::gmock ) @@ -48,11 +49,23 @@ if(UNIT_TEST_SOURCES) PRIVATE ${LIVEKIT_ROOT_DIR}/include ${LIVEKIT_ROOT_DIR}/src + ${LIVEKIT_BINARY_DIR}/generated + ${Protobuf_INCLUDE_DIRS} ) + if(TARGET absl::base) + get_target_property(_livekit_unit_test_absl_inc absl::base INTERFACE_INCLUDE_DIRECTORIES) + if(_livekit_unit_test_absl_inc) + target_include_directories(livekit_unit_tests PRIVATE + ${_livekit_unit_test_absl_inc} + ) + endif() + endif() target_compile_definitions(livekit_unit_tests PRIVATE LIVEKIT_TEST_ACCESS + LIVEKIT_ROOT_DIR="${LIVEKIT_ROOT_DIR}" + SPDLOG_ACTIVE_LEVEL=${_SPDLOG_ACTIVE_LEVEL} ) if(WIN32) diff --git a/src/tests/integration/test_audio_processing_module.cpp b/src/tests/unit/test_audio_processing_module.cpp similarity index 99% rename from src/tests/integration/test_audio_processing_module.cpp rename to src/tests/unit/test_audio_processing_module.cpp index 4c4b48c..3bfcb41 100644 --- a/src/tests/integration/test_audio_processing_module.cpp +++ b/src/tests/unit/test_audio_processing_module.cpp @@ -801,6 +801,7 @@ TEST_F(AudioProcessingModuleTest, AGCAttenuatesLoudSpeech) { int sample_rate = 0; int num_channels = 0; + // TODO: figure out what generates this welcome.wav file such that this test isn't skipped std::string wav_path = std::string(LIVEKIT_ROOT_DIR) + "/data/welcome.wav"; if (!readWavFile(wav_path, original_samples, sample_rate, num_channels)) { GTEST_SKIP() << "Could not read " << wav_path; diff --git a/src/tests/integration/test_logging.cpp b/src/tests/unit/test_logging.cpp similarity index 100% rename from src/tests/integration/test_logging.cpp rename to src/tests/unit/test_logging.cpp diff --git a/src/tests/integration/test_room_callbacks.cpp b/src/tests/unit/test_room_callbacks.cpp similarity index 100% rename from src/tests/integration/test_room_callbacks.cpp rename to src/tests/unit/test_room_callbacks.cpp diff --git a/src/tests/integration/test_sdk_initialization.cpp b/src/tests/unit/test_sdk_initialization.cpp similarity index 100% rename from src/tests/integration/test_sdk_initialization.cpp rename to src/tests/unit/test_sdk_initialization.cpp diff --git a/src/tests/integration/test_subscription_thread_dispatcher.cpp b/src/tests/unit/test_subscription_thread_dispatcher.cpp similarity index 100% rename from src/tests/integration/test_subscription_thread_dispatcher.cpp rename to src/tests/unit/test_subscription_thread_dispatcher.cpp From 7df66505e04c84d2598239538ffcc4f97113f904 Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 16:57:55 -0600 Subject: [PATCH 07/11] Separate quality stage --- .github/workflows/builds.yml | 232 ++++++++++++++++++----------------- 1 file changed, 120 insertions(+), 112 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 9af3068..e8ca34c 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -51,35 +51,24 @@ jobs: include: - os: ubuntu-latest name: linux-x64 - build_cmd: ./build.sh release-examples + build_cmd: ./build.sh release-tests build_dir: build-release - test_preset: linux-release-tests - run_tests: true - os: ubuntu-24.04-arm name: linux-arm64 - build_cmd: ./build.sh release-examples + build_cmd: ./build.sh release-tests build_dir: build-release - test_preset: linux-release-tests - run_tests: true - os: macos-latest name: macos-arm64 - build_cmd: ./build.sh release-examples + build_cmd: ./build.sh release-tests build_dir: build-release - test_preset: macos-release-tests - run_tests: true - os: macos-latest name: macos-x64 - build_cmd: ./build.sh release-examples --macos-arch x86_64 + build_cmd: ./build.sh release-tests --macos-arch x86_64 build_dir: build-release - test_preset: macos-release-tests - test_cmake_args: -DCMAKE_OSX_ARCHITECTURES=x86_64 - run_tests: true - os: windows-latest name: windows-x64 - build_cmd: .\build.cmd release-examples + build_cmd: .\build.cmd release-tests build_dir: build-release - test_preset: windows-release-tests - run_tests: true name: Build (${{ matrix.name }}) runs-on: ${{ matrix.os }} @@ -89,7 +78,7 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive - fetch-depth: 0 + fetch-depth: 1 # ---------- vcpkg caching for Windows ---------- - name: Export GitHub Actions cache environment variables @@ -180,101 +169,70 @@ jobs: shell: pwsh run: ${{ matrix.build_cmd }} - # ---------- Smoke test examples ---------- - - name: Smoke test examples (Unix) - if: runner.os != 'Windows' - shell: bash - run: | - set -x - failed=false - for exe in SimpleRoom SimpleRpc SimpleDataStream; do - exe_path="${{ matrix.build_dir }}/bin/${exe}" - if [[ -x "${exe_path}" ]]; then - echo "Testing ${exe}..." - output=$("${exe_path}" --help 2>&1) || true - if [[ -z "${output}" ]]; then - echo "ERROR: ${exe} produced no output" - failed=true - else - echo "${output}" - echo "${exe} ran successfully" - fi - else - echo "ERROR: ${exe_path} not found or not executable" - failed=true - fi - done - if [[ "$failed" == "true" ]]; then exit 1; fi - - - name: Smoke test examples (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: | - $ErrorActionPreference = 'Continue' - $examples = @('SimpleRoom', 'SimpleRpc', 'SimpleDataStream') - $failed = $false - foreach ($exe in $examples) { - $exePath = "${{ matrix.build_dir }}/bin/${exe}.exe" - if (Test-Path $exePath) { - Write-Host "Testing ${exe}..." - $pinfo = New-Object System.Diagnostics.ProcessStartInfo - $pinfo.FileName = $exePath - $pinfo.Arguments = "--help" - $pinfo.RedirectStandardOutput = $true - $pinfo.RedirectStandardError = $true - $pinfo.UseShellExecute = $false - $p = New-Object System.Diagnostics.Process - $p.StartInfo = $pinfo - $p.Start() | Out-Null - $stdout = $p.StandardOutput.ReadToEnd() - $stderr = $p.StandardError.ReadToEnd() - $p.WaitForExit() - $output = $stdout + $stderr - if ([string]::IsNullOrWhiteSpace($output)) { - Write-Host "ERROR: ${exe} produced no output" - $failed = $true - } else { - Write-Host $output - Write-Host "${exe} ran successfully" - } - } else { - Write-Host "ERROR: ${exePath} not found" - $failed = $true - } - } - if ($failed) { exit 1 } else { exit 0 } - - # ---------- Build and run tests ---------- - - name: Configure tests - if: matrix.run_tests - run: cmake --preset ${{ matrix.test_preset }} ${{ matrix.test_cmake_args }} - - - name: Build unit tests - if: matrix.run_tests - run: cmake --build ${{ matrix.build_dir }} --config Release --target livekit_unit_tests - - - name: Run unit tests (Unix) - if: runner.os != 'Windows' && matrix.run_tests - shell: bash - run: | - ${{ matrix.build_dir }}/bin/livekit_unit_tests \ - --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml - - - name: Run unit tests (Windows) - if: runner.os == 'Windows' && matrix.run_tests - shell: pwsh - run: | - & "${{ matrix.build_dir }}/bin/livekit_unit_tests.exe" ` - --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml - - - name: Upload test results - if: always() && matrix.run_tests - uses: actions/upload-artifact@v4 - with: - name: test-results-${{ matrix.name }} - path: | - ${{ matrix.build_dir }}/unit-test-results.xml - retention-days: 7 + # TODO: Re-enable smoke tests once examples are built alongside tests + # # ---------- Smoke test examples ---------- + # - name: Smoke test examples (Unix) + # if: runner.os != 'Windows' + # shell: bash + # run: | + # set -x + # failed=false + # for exe in SimpleRoom SimpleRpc SimpleDataStream; do + # exe_path="${{ matrix.build_dir }}/bin/${exe}" + # if [[ -x "${exe_path}" ]]; then + # echo "Testing ${exe}..." + # output=$("${exe_path}" --help 2>&1) || true + # if [[ -z "${output}" ]]; then + # echo "ERROR: ${exe} produced no output" + # failed=true + # else + # echo "${output}" + # echo "${exe} ran successfully" + # fi + # else + # echo "ERROR: ${exe_path} not found or not executable" + # failed=true + # fi + # done + # if [[ "$failed" == "true" ]]; then exit 1; fi + # + # - name: Smoke test examples (Windows) + # if: runner.os == 'Windows' + # shell: pwsh + # run: | + # $ErrorActionPreference = 'Continue' + # $examples = @('SimpleRoom', 'SimpleRpc', 'SimpleDataStream') + # $failed = $false + # foreach ($exe in $examples) { + # $exePath = "${{ matrix.build_dir }}/bin/${exe}.exe" + # if (Test-Path $exePath) { + # Write-Host "Testing ${exe}..." + # $pinfo = New-Object System.Diagnostics.ProcessStartInfo + # $pinfo.FileName = $exePath + # $pinfo.Arguments = "--help" + # $pinfo.RedirectStandardOutput = $true + # $pinfo.RedirectStandardError = $true + # $pinfo.UseShellExecute = $false + # $p = New-Object System.Diagnostics.Process + # $p.StartInfo = $pinfo + # $p.Start() | Out-Null + # $stdout = $p.StandardOutput.ReadToEnd() + # $stderr = $p.StandardError.ReadToEnd() + # $p.WaitForExit() + # $output = $stdout + $stderr + # if ([string]::IsNullOrWhiteSpace($output)) { + # Write-Host "ERROR: ${exe} produced no output" + # $failed = $true + # } else { + # Write-Host $output + # Write-Host "${exe} ran successfully" + # } + # } else { + # Write-Host "ERROR: ${exePath} not found" + # $failed = $true + # } + # } + # if ($failed) { exit 1 } else { exit 0 } # ---------- Upload artifacts ---------- - name: Upload build artifacts @@ -298,6 +256,56 @@ jobs: ./build.sh clean-all || true fi + quality: + needs: build + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + name: linux-x64 + - os: ubuntu-24.04-arm + name: linux-arm64 + - os: macos-latest + name: macos-arm64 + - os: macos-latest + name: macos-x64 + - os: windows-latest + name: windows-x64 + + name: Quality (${{ matrix.name }}) + runs-on: ${{ matrix.os }} + + steps: + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: livekit-sdk-${{ matrix.name }} + path: build-release + + - name: Run unit tests (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + chmod +x build-release/bin/livekit_unit_tests + build-release/bin/livekit_unit_tests \ + --gtest_output=xml:unit-test-results.xml + + - name: Run unit tests (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + & "build-release/bin/livekit_unit_tests.exe" ` + --gtest_output=xml:unit-test-results.xml + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ matrix.name }} + path: unit-test-results.xml + retention-days: 7 + docker-build-x64: name: Build (docker-linux-x64) runs-on: ubuntu-latest From a7e5f0f4740584339b705d2c0c9e6513713ef7a4 Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 19:16:49 -0600 Subject: [PATCH 08/11] unify test stage --- .github/workflows/builds.yml | 136 ++++++----------------------------- 1 file changed, 22 insertions(+), 114 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index e8ca34c..126544f 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -169,70 +169,28 @@ jobs: shell: pwsh run: ${{ matrix.build_cmd }} - # TODO: Re-enable smoke tests once examples are built alongside tests - # # ---------- Smoke test examples ---------- - # - name: Smoke test examples (Unix) - # if: runner.os != 'Windows' - # shell: bash - # run: | - # set -x - # failed=false - # for exe in SimpleRoom SimpleRpc SimpleDataStream; do - # exe_path="${{ matrix.build_dir }}/bin/${exe}" - # if [[ -x "${exe_path}" ]]; then - # echo "Testing ${exe}..." - # output=$("${exe_path}" --help 2>&1) || true - # if [[ -z "${output}" ]]; then - # echo "ERROR: ${exe} produced no output" - # failed=true - # else - # echo "${output}" - # echo "${exe} ran successfully" - # fi - # else - # echo "ERROR: ${exe_path} not found or not executable" - # failed=true - # fi - # done - # if [[ "$failed" == "true" ]]; then exit 1; fi - # - # - name: Smoke test examples (Windows) - # if: runner.os == 'Windows' - # shell: pwsh - # run: | - # $ErrorActionPreference = 'Continue' - # $examples = @('SimpleRoom', 'SimpleRpc', 'SimpleDataStream') - # $failed = $false - # foreach ($exe in $examples) { - # $exePath = "${{ matrix.build_dir }}/bin/${exe}.exe" - # if (Test-Path $exePath) { - # Write-Host "Testing ${exe}..." - # $pinfo = New-Object System.Diagnostics.ProcessStartInfo - # $pinfo.FileName = $exePath - # $pinfo.Arguments = "--help" - # $pinfo.RedirectStandardOutput = $true - # $pinfo.RedirectStandardError = $true - # $pinfo.UseShellExecute = $false - # $p = New-Object System.Diagnostics.Process - # $p.StartInfo = $pinfo - # $p.Start() | Out-Null - # $stdout = $p.StandardOutput.ReadToEnd() - # $stderr = $p.StandardError.ReadToEnd() - # $p.WaitForExit() - # $output = $stdout + $stderr - # if ([string]::IsNullOrWhiteSpace($output)) { - # Write-Host "ERROR: ${exe} produced no output" - # $failed = $true - # } else { - # Write-Host $output - # Write-Host "${exe} ran successfully" - # } - # } else { - # Write-Host "ERROR: ${exePath} not found" - # $failed = $true - # } - # } - # if ($failed) { exit 1 } else { exit 0 } + # ---------- Run unit tests ---------- + - name: Run unit tests (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + ${{ matrix.build_dir }}/bin/livekit_unit_tests \ + --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml + + - name: Run unit tests (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + & "${{ matrix.build_dir }}/bin/livekit_unit_tests.exe" ` + --gtest_output=xml:${{ matrix.build_dir }}/unit-test-results.xml + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ matrix.name }} + path: ${{ matrix.build_dir }}/unit-test-results.xml + retention-days: 7 # ---------- Upload artifacts ---------- - name: Upload build artifacts @@ -256,56 +214,6 @@ jobs: ./build.sh clean-all || true fi - quality: - needs: build - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - name: linux-x64 - - os: ubuntu-24.04-arm - name: linux-arm64 - - os: macos-latest - name: macos-arm64 - - os: macos-latest - name: macos-x64 - - os: windows-latest - name: windows-x64 - - name: Quality (${{ matrix.name }}) - runs-on: ${{ matrix.os }} - - steps: - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - name: livekit-sdk-${{ matrix.name }} - path: build-release - - - name: Run unit tests (Unix) - if: runner.os != 'Windows' - shell: bash - run: | - chmod +x build-release/bin/livekit_unit_tests - build-release/bin/livekit_unit_tests \ - --gtest_output=xml:unit-test-results.xml - - - name: Run unit tests (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: | - & "build-release/bin/livekit_unit_tests.exe" ` - --gtest_output=xml:unit-test-results.xml - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results-${{ matrix.name }} - path: unit-test-results.xml - retention-days: 7 - docker-build-x64: name: Build (docker-linux-x64) runs-on: ubuntu-latest From b98cb971f71c1cb2a91323f4316b019f5f91409f Mon Sep 17 00:00:00 2001 From: Alan George Date: Thu, 9 Apr 2026 21:26:47 -0600 Subject: [PATCH 09/11] Possibly fix windows --- src/tests/CMakeLists.txt | 7 +++++++ src/tests/stress/test_latency_measurement.cpp | 1 + src/tests/unit/test_audio_processing_module.cpp | 1 + src/tests/unit/test_room_callbacks.cpp | 4 ++-- src/tests/unit/test_subscription_thread_dispatcher.cpp | 6 +++--- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 02d942c..bfd973e 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -122,6 +122,13 @@ if(INTEGRATION_TEST_SOURCES) ${INTEGRATION_TEST_SOURCES} ) + # On Windows, protobuf default-instance symbols (constinit globals) are not + # auto-exported from livekit.dll by WINDOWS_EXPORT_ALL_SYMBOLS. Link the + # proto object library directly so the test binary has its own copy. + if(WIN32 AND TARGET livekit_proto) + target_sources(livekit_integration_tests PRIVATE $) + endif() + target_link_libraries(livekit_integration_tests PRIVATE livekit diff --git a/src/tests/stress/test_latency_measurement.cpp b/src/tests/stress/test_latency_measurement.cpp index e93d210..1d1107b 100644 --- a/src/tests/stress/test_latency_measurement.cpp +++ b/src/tests/stress/test_latency_measurement.cpp @@ -15,6 +15,7 @@ */ #include "../common/test_common.h" +#define _USE_MATH_DEFINES #include #include #include diff --git a/src/tests/unit/test_audio_processing_module.cpp b/src/tests/unit/test_audio_processing_module.cpp index 3bfcb41..dfd5afb 100644 --- a/src/tests/unit/test_audio_processing_module.cpp +++ b/src/tests/unit/test_audio_processing_module.cpp @@ -20,6 +20,7 @@ #include #include +#define _USE_MATH_DEFINES #include #include #include diff --git a/src/tests/unit/test_room_callbacks.cpp b/src/tests/unit/test_room_callbacks.cpp index fe75921..90ac35b 100644 --- a/src/tests/unit/test_room_callbacks.cpp +++ b/src/tests/unit/test_room_callbacks.cpp @@ -202,7 +202,7 @@ TEST_F(RoomCallbackTest, ConcurrentRegistrationDoesNotCrash) { threads.reserve(kThreads); for (int t = 0; t < kThreads; ++t) { - threads.emplace_back([&room, t]() { + threads.emplace_back([&room, t, kIterations]() { for (int i = 0; i < kIterations; ++i) { const std::string id = "participant-" + std::to_string(t); room.setOnAudioFrameCallback(id, TrackSource::SOURCE_MICROPHONE, @@ -228,7 +228,7 @@ TEST_F(RoomCallbackTest, ConcurrentMixedRegistrationDoesNotCrash) { threads.reserve(kThreads); for (int t = 0; t < kThreads; ++t) { - threads.emplace_back([&room, t]() { + threads.emplace_back([&room, t, kIterations]() { const std::string id = "p-" + std::to_string(t); for (int i = 0; i < kIterations; ++i) { room.setOnAudioFrameCallback(id, TrackSource::SOURCE_MICROPHONE, diff --git a/src/tests/unit/test_subscription_thread_dispatcher.cpp b/src/tests/unit/test_subscription_thread_dispatcher.cpp index 26c2185..bb3bdfd 100644 --- a/src/tests/unit/test_subscription_thread_dispatcher.cpp +++ b/src/tests/unit/test_subscription_thread_dispatcher.cpp @@ -407,7 +407,7 @@ TEST_F(SubscriptionThreadDispatcherTest, ConcurrentRegistrationDoesNotCrash) { threads.reserve(kThreads); for (int t = 0; t < kThreads; ++t) { - threads.emplace_back([&dispatcher, t]() { + threads.emplace_back([&dispatcher, t, kIterations]() { for (int i = 0; i < kIterations; ++i) { std::string id = "participant-" + std::to_string(t); dispatcher.setOnAudioFrameCallback(id, TrackSource::SOURCE_MICROPHONE, @@ -435,7 +435,7 @@ TEST_F(SubscriptionThreadDispatcherTest, std::vector threads; for (int t = 0; t < kThreads; ++t) { - threads.emplace_back([&dispatcher, t]() { + threads.emplace_back([&dispatcher, t, kIterations]() { std::string id = "p-" + std::to_string(t); for (int i = 0; i < kIterations; ++i) { dispatcher.setOnAudioFrameCallback(id, TrackSource::SOURCE_MICROPHONE, @@ -714,7 +714,7 @@ TEST_F(SubscriptionThreadDispatcherTest, threads.reserve(kThreads); for (int t = 0; t < kThreads; ++t) { - threads.emplace_back([&dispatcher, t]() { + threads.emplace_back([&dispatcher, t, kIterations]() { for (int i = 0; i < kIterations; ++i) { auto id = dispatcher.addOnDataFrameCallback( "participant-" + std::to_string(t), "track", From e3362e9fc7fe4a142f45a014d5e872257a1f5b1d Mon Sep 17 00:00:00 2001 From: Alan George Date: Fri, 10 Apr 2026 09:30:52 -0600 Subject: [PATCH 10/11] Use full sha on actions, fixes to windows build --- .github/workflows/builds.yml | 2 +- bridge/include/livekit_bridge/rpc_constants.h | 23 ++++++++++++++----- src/tests/CMakeLists.txt | 7 ++++++ src/tests/stress/test_latency_measurement.cpp | 1 - .../unit/test_audio_processing_module.cpp | 1 - 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 200def2..77254c8 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -198,7 +198,7 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: test-results-${{ matrix.name }} path: ${{ matrix.build_dir }}/unit-test-results.xml diff --git a/bridge/include/livekit_bridge/rpc_constants.h b/bridge/include/livekit_bridge/rpc_constants.h index 3511239..2c08df9 100644 --- a/bridge/include/livekit_bridge/rpc_constants.h +++ b/bridge/include/livekit_bridge/rpc_constants.h @@ -21,6 +21,16 @@ #include +#ifdef _WIN32 +#ifdef livekit_bridge_EXPORTS +#define LIVEKIT_BRIDGE_API __declspec(dllexport) +#else +#define LIVEKIT_BRIDGE_API __declspec(dllimport) +#endif +#else +#define LIVEKIT_BRIDGE_API +#endif + namespace livekit_bridge { namespace rpc { @@ -34,20 +44,21 @@ namespace track_control { enum class Action { kActionMute, kActionUnmute }; /// RPC method name registered by the bridge for remote track control. -extern const char *const kMethod; +LIVEKIT_BRIDGE_API extern const char *const kMethod; /// Payload action strings. -extern const char *const kActionMute; -extern const char *const kActionUnmute; +LIVEKIT_BRIDGE_API extern const char *const kActionMute; +LIVEKIT_BRIDGE_API extern const char *const kActionUnmute; /// Delimiter between action and track name in the payload (e.g. "mute:cam"). -extern const char kDelimiter; +LIVEKIT_BRIDGE_API extern const char kDelimiter; /// Response payload returned on success. -extern const char *const kResponseOk; +LIVEKIT_BRIDGE_API extern const char *const kResponseOk; /// Build a track-control RPC payload: ":". -std::string formatPayload(const char *action, const std::string &track_name); +LIVEKIT_BRIDGE_API std::string formatPayload(const char *action, + const std::string &track_name); } // namespace track_control } // namespace rpc diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index bfd973e..a8c0124 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -66,6 +66,7 @@ if(UNIT_TEST_SOURCES) LIVEKIT_TEST_ACCESS LIVEKIT_ROOT_DIR="${LIVEKIT_ROOT_DIR}" SPDLOG_ACTIVE_LEVEL=${_SPDLOG_ACTIVE_LEVEL} + $<$:_USE_MATH_DEFINES> ) if(WIN32) @@ -158,6 +159,7 @@ if(INTEGRATION_TEST_SOURCES) LIVEKIT_TEST_ACCESS LIVEKIT_ROOT_DIR="${LIVEKIT_ROOT_DIR}" SPDLOG_ACTIVE_LEVEL=${_SPDLOG_ACTIVE_LEVEL} + $<$:_USE_MATH_DEFINES> ) # Copy shared libraries to test executable directory @@ -229,6 +231,11 @@ if(STRESS_TEST_SOURCES) ${LIVEKIT_ROOT_DIR}/src ) + target_compile_definitions(livekit_stress_tests + PRIVATE + $<$:_USE_MATH_DEFINES> + ) + # Copy shared libraries to test executable directory if(WIN32) add_custom_command(TARGET livekit_stress_tests POST_BUILD diff --git a/src/tests/stress/test_latency_measurement.cpp b/src/tests/stress/test_latency_measurement.cpp index 1d1107b..e93d210 100644 --- a/src/tests/stress/test_latency_measurement.cpp +++ b/src/tests/stress/test_latency_measurement.cpp @@ -15,7 +15,6 @@ */ #include "../common/test_common.h" -#define _USE_MATH_DEFINES #include #include #include diff --git a/src/tests/unit/test_audio_processing_module.cpp b/src/tests/unit/test_audio_processing_module.cpp index dfd5afb..3bfcb41 100644 --- a/src/tests/unit/test_audio_processing_module.cpp +++ b/src/tests/unit/test_audio_processing_module.cpp @@ -20,7 +20,6 @@ #include #include -#define _USE_MATH_DEFINES #include #include #include From 498ea01f1bde830f453e776fc95a44c0786c9227 Mon Sep 17 00:00:00 2001 From: Alan George Date: Fri, 10 Apr 2026 13:42:45 -0600 Subject: [PATCH 11/11] Fix integration stage build on Windows --- src/tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index a8c0124..22067e8 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -134,6 +134,7 @@ if(INTEGRATION_TEST_SOURCES) PRIVATE livekit spdlog::spdlog + $<$:${LIVEKIT_PROTOBUF_TARGET}> GTest::gtest_main GTest::gmock )