cmake_minimum_required(VERSION 3.21) # ── Catch2 ──────────────────────────────────────────────────────────────────── find_package(Catch2 3 QUIET) if(NOT Catch2_FOUND) include(FetchContent) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.5.3 ) FetchContent_MakeAvailable(Catch2) endif() # ── Google Test ─────────────────────────────────────────────────────────────── find_package(GTest QUIET) if(NOT GTest_FOUND) include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0 ) FetchContent_MakeAvailable(googletest) endif() # ── Test executable ─────────────────────────────────────────────────────────── add_executable(kpn_tests test_fixed_string.cpp test_traits.cpp test_channel.cpp test_node.cpp test_network.cpp test_static_network.cpp test_shared_resource.cpp test_pool_node.cpp test_backpressure_deadlock.cpp test_scheduler.cpp test_submit_gate.cpp ) target_link_libraries(kpn_tests PRIVATE kpn Catch2::Catch2WithMain GTest::gtest ) # ── Channel stress suite (separate executable) ──────────────────────────────── # Contended SPSC tests for the lock-free Channel. Kept out of kpn_tests # because each case runs many reps / tens of thousands of items and is slow. # Most valuable under -DKPN_SANITIZER=thread, but correct (and run) without it. add_executable(kpn_tests_stress test_channel_stress.cpp) target_link_libraries(kpn_tests_stress PRIVATE kpn Catch2::Catch2WithMain) # ── Wedge soak (PERF_PLAN G1) ───────────────────────────────────────────────── # Long-running end-to-end loop over the configurations that historically wedged. # Always built, so it cannot rot, but its CTest cases are registered only under # -DKPN_ENABLE_SOAK_TESTS=ON: they run for minutes and would otherwise dominate # every `ctest` invocation. Performance work runs it before and after a change: # # cmake -B build -DKPN_ENABLE_SOAK_TESTS=ON -DKPN_SOAK_ITERS=50000 # cmake --build build --target kpn_soak_wedge # ctest --test-dir build -L soak # # The binary self-diagnoses: an iteration that stops making progress trips a # watchdog that aborts naming the iteration and phase, rather than hanging. add_executable(kpn_soak_wedge soak_wedge.cpp) target_link_libraries(kpn_soak_wedge PRIVATE kpn) target_compile_options(kpn_soak_wedge PRIVATE -O2) option(KPN_ENABLE_SOAK_TESTS "Register the wedge soak cases with CTest" OFF) set(KPN_SOAK_ITERS 5000 CACHE STRING "Iterations per wedge soak case") # ── Sanitizer flags ─────────────────────────────────────────────────────────── # kpn_sanitizer_flags() is defined in the top-level CMakeLists and is a no-op # unless -DKPN_SANITIZER=... is set. Sanitizer must be on both compile and link. kpn_sanitizer_flags(_kpn_san) if(_kpn_san) foreach(_t kpn_tests kpn_tests_stress kpn_soak_wedge) target_compile_options(${_t} PRIVATE ${_kpn_san}) target_link_options(${_t} PRIVATE ${_kpn_san}) endforeach() endif() include(CTest) include(Catch) # DISCOVERY_MODE PRE_TEST defers test enumeration to `ctest` run time. The # default (POST_BUILD) runs each test binary during the build to list its # cases — which fails a sanitizer build: a TSan/ASan binary needs a fixed # address-space layout and aborts on startup ("unexpected memory mapping") # under the container's ASLR, breaking the build before any test runs. The # tsan.yaml job invokes the binaries directly (not via ctest), so deferring # discovery costs nothing there and keeps `ctest` working for normal builds. catch_discover_tests(kpn_tests DISCOVERY_MODE PRE_TEST) # Register the stress suite under its own label so CI can run / time it # separately from the fast unit tests. catch_discover_tests(kpn_tests_stress DISCOVERY_MODE PRE_TEST PROPERTIES LABELS "stress") if(KPN_ENABLE_SOAK_TESTS) # pool: the configuration the August wedges were reproduced on. add_test(NAME soak.wedge.pool COMMAND kpn_soak_wedge --mode=pool --depth=4 --threads=4 --items=1000 --work-us=10 --iters=${KPN_SOAK_ITERS}) # private: one pool per node — the model workstream A would change. add_test(NAME soak.wedge.private COMMAND kpn_soak_wedge --mode=priv --depth=8 --items=1000 --work-us=10 --iters=${KPN_SOAK_ITERS}) set_tests_properties(soak.wedge.pool soak.wedge.private PROPERTIES LABELS "soak" TIMEOUT 3600) endif()