This commit implements a complete test infrastructure for validating hot-reload stability and robustness across multiple scenarios. ## New Test Infrastructure ### Test Helpers (tests/helpers/) - TestMetrics: FPS, memory, reload time tracking with statistics - TestReporter: Assertion tracking and formatted test reports - SystemUtils: Memory usage monitoring via /proc/self/status - TestAssertions: Macro-based assertion framework ### Test Modules - TankModule: Realistic module with 50 tanks for production testing - ChaosModule: Crash-injection module for robustness validation - StressModule: Lightweight module for long-duration stability tests ## Integration Test Scenarios ### Scenario 1: Production Hot-Reload (test_01_production_hotreload.cpp) ✅ PASSED - End-to-end hot-reload validation - 30 seconds simulation (1800 frames @ 60 FPS) - TankModule with 50 tanks, realistic state - Source modification (v1.0 → v2.0), recompilation, reload - State preservation: positions, velocities, frameCount - Metrics: ~163ms reload time, 0.88MB memory growth ### Scenario 2: Chaos Monkey (test_02_chaos_monkey.cpp) ✅ PASSED - Extreme robustness testing - 150+ random crashes per run (5% crash probability per frame) - 5 crash types: runtime_error, logic_error, out_of_range, domain_error, state corruption - 100% recovery rate via automatic hot-reload - Corrupted state detection and rejection - Random seed for unpredictable crash patterns - Proof of real reload: temporary files in /tmp/grove_module_*.so ### Scenario 3: Stress Test (test_03_stress_test.cpp) ✅ PASSED - Long-duration stability validation - 10 minutes simulation (36000 frames @ 60 FPS) - 120 hot-reloads (every 5 seconds) - 100% reload success rate (120/120) - Memory growth: 2 MB (threshold: 50 MB) - Avg reload time: 160ms (threshold: 500ms) - No memory leaks, no file descriptor leaks ## Core Engine Enhancements ### ModuleLoader (src/ModuleLoader.cpp) - Temporary file copy to /tmp/ for Linux dlopen cache bypass - Robust reload() method: getState() → unload() → load() → setState() - Automatic cleanup of temporary files - Comprehensive error handling and logging ### DebugEngine (src/DebugEngine.cpp) - Automatic recovery in processModuleSystems() - Exception catching → logging → module reload → continue - Module state dump utilities for debugging ### SequentialModuleSystem (src/SequentialModuleSystem.cpp) - extractModule() for safe module extraction - registerModule() for module re-registration - Enhanced processModules() with error handling ## Build System - CMake configuration for test infrastructure - Shared library compilation for test modules (.so) - CTest integration for all scenarios - PIC flag management for spdlog compatibility ## Documentation (planTI/) - Complete test architecture documentation - Detailed scenario specifications with success criteria - Global test plan and validation thresholds ## Validation Results All 3 integration scenarios pass successfully: - Production hot-reload: State preservation validated - Chaos Monkey: 100% recovery from 150+ crashes - Stress Test: Stable over 120 reloads, minimal memory growth 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
165 lines
4.3 KiB
CMake
165 lines
4.3 KiB
CMake
# Hot-reload test suite
|
|
|
|
# Test module as shared library (.so) for hot-reload
|
|
add_library(TestModule SHARED
|
|
modules/TestModule.cpp
|
|
)
|
|
|
|
target_link_libraries(TestModule PRIVATE
|
|
GroveEngine::core
|
|
GroveEngine::impl # For JsonDataNode implementation
|
|
)
|
|
|
|
# Don't add "lib" prefix on Linux (we want TestModule.so, not libTestModule.so)
|
|
set_target_properties(TestModule PROPERTIES PREFIX "lib")
|
|
set_target_properties(TestModule PROPERTIES OUTPUT_NAME "TestModule")
|
|
|
|
# Basic hot-reload test executable (manual dlopen/dlclose)
|
|
add_executable(test_hotreload
|
|
hotreload/test_hotreload.cpp
|
|
)
|
|
|
|
target_link_libraries(test_hotreload PRIVATE
|
|
GroveEngine::core
|
|
GroveEngine::impl # For JsonDataNode implementation
|
|
${CMAKE_DL_LIBS} # For dlopen/dlclose
|
|
)
|
|
|
|
# Make sure test module is built before test executable
|
|
add_dependencies(test_hotreload TestModule)
|
|
|
|
# Copy test module to test executable directory after build
|
|
add_custom_command(TARGET test_hotreload POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E copy
|
|
$<TARGET_FILE:TestModule>
|
|
$<TARGET_FILE_DIR:test_hotreload>/
|
|
COMMENT "Copying TestModule.so to test directory"
|
|
)
|
|
|
|
# Engine hot-reload test (uses DebugEngine + SequentialModuleSystem + FileWatcher)
|
|
add_executable(test_engine_hotreload
|
|
hotreload/test_engine_hotreload.cpp
|
|
)
|
|
|
|
target_link_libraries(test_engine_hotreload PRIVATE
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
${CMAKE_DL_LIBS}
|
|
)
|
|
|
|
add_dependencies(test_engine_hotreload TestModule)
|
|
|
|
add_custom_command(TARGET test_engine_hotreload POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E copy
|
|
$<TARGET_FILE:TestModule>
|
|
$<TARGET_FILE_DIR:test_engine_hotreload>/
|
|
COMMENT "Copying TestModule.so to engine test directory"
|
|
)
|
|
|
|
# ================================================================================
|
|
# Integration Tests
|
|
# ================================================================================
|
|
|
|
# Helpers library (partagée par tous les tests)
|
|
add_library(test_helpers STATIC
|
|
helpers/TestMetrics.cpp
|
|
helpers/TestReporter.cpp
|
|
helpers/SystemUtils.cpp
|
|
)
|
|
|
|
target_include_directories(test_helpers PUBLIC
|
|
${CMAKE_CURRENT_SOURCE_DIR}
|
|
)
|
|
|
|
target_link_libraries(test_helpers PUBLIC
|
|
GroveEngine::core
|
|
spdlog::spdlog
|
|
)
|
|
|
|
# Set PIC for static library
|
|
set_target_properties(test_helpers PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
|
|
# TankModule pour tests d'intégration
|
|
add_library(TankModule SHARED
|
|
modules/TankModule.cpp
|
|
)
|
|
|
|
target_link_libraries(TankModule PRIVATE
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
spdlog::spdlog
|
|
)
|
|
|
|
# Ensure spdlog is compiled with PIC
|
|
set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
|
|
# Test 01: Production Hot-Reload
|
|
add_executable(test_01_production_hotreload
|
|
integration/test_01_production_hotreload.cpp
|
|
)
|
|
|
|
target_link_libraries(test_01_production_hotreload PRIVATE
|
|
test_helpers
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
)
|
|
|
|
add_dependencies(test_01_production_hotreload TankModule)
|
|
|
|
# CTest integration
|
|
add_test(NAME ProductionHotReload COMMAND test_01_production_hotreload)
|
|
|
|
# ChaosModule pour tests de robustesse
|
|
add_library(ChaosModule SHARED
|
|
modules/ChaosModule.cpp
|
|
)
|
|
|
|
target_link_libraries(ChaosModule PRIVATE
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
spdlog::spdlog
|
|
)
|
|
|
|
# Test 02: Chaos Monkey
|
|
add_executable(test_02_chaos_monkey
|
|
integration/test_02_chaos_monkey.cpp
|
|
)
|
|
|
|
target_link_libraries(test_02_chaos_monkey PRIVATE
|
|
test_helpers
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
)
|
|
|
|
add_dependencies(test_02_chaos_monkey ChaosModule)
|
|
|
|
# CTest integration
|
|
add_test(NAME ChaosMonkey COMMAND test_02_chaos_monkey)
|
|
|
|
# StressModule pour tests de stabilité long-terme
|
|
add_library(StressModule SHARED
|
|
modules/StressModule.cpp
|
|
)
|
|
|
|
target_link_libraries(StressModule PRIVATE
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
spdlog::spdlog
|
|
)
|
|
|
|
# Test 03: Stress Test - 10 minutes stability
|
|
add_executable(test_03_stress_test
|
|
integration/test_03_stress_test.cpp
|
|
)
|
|
|
|
target_link_libraries(test_03_stress_test PRIVATE
|
|
test_helpers
|
|
GroveEngine::core
|
|
GroveEngine::impl
|
|
)
|
|
|
|
add_dependencies(test_03_stress_test StressModule)
|
|
|
|
# CTest integration
|
|
add_test(NAME StressTest COMMAND test_03_stress_test)
|