Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,22 @@ jobs:
uses: actions/checkout@v5
with:
submodules: recursive
- name: Install lcov
run: sudo apt-get update && sudo apt-get install -y lcov
- name: Build and test using install.sh
run: |
chmod +x install.sh
sudo ./install.sh
./install.sh
- name: Calculate coverage
run: |
# Activate conda from wherever install.sh set it up
if [ -f "$HOME/miniconda3/etc/profile.d/conda.sh" ]; then
source "$HOME/miniconda3/etc/profile.d/conda.sh"
elif [ -f "$HOME/anaconda3/etc/profile.d/conda.sh" ]; then
source "$HOME/anaconda3/etc/profile.d/conda.sh"
elif command -v conda &>/dev/null; then
eval "$(conda shell.bash hook)"
fi
conda activate iowarp
SITE_NAME=${{ contains(matrix.os, 'arm') && '"ubu-24.arm64"' || '"ubu-24.amd64"' }}
./CI/calculate_coverage.sh --all --clean --site ${SITE_NAME}
63 changes: 45 additions & 18 deletions CI/calculate_coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
# --run-distributed Run distributed tests (requires Docker)
# --all Build and run all tests (equivalent to --build --run-ctest --run-distributed)
# --clean Clean build directory before starting
# --site SITE_NAME Submit results to CDash with the given site name
# --help Show this help message
#
# Examples:
# ./CI/calculate_coverage.sh # Just generate reports from existing data
# ./CI/calculate_coverage.sh --all # Full build + test + report generation
# ./CI/calculate_coverage.sh --run-ctest # Run CTest and generate reports
# ./CI/calculate_coverage.sh --all --site ubu-24.amd64 # Full run + CDash submit
#
################################################################################

Expand All @@ -36,6 +38,7 @@ DO_BUILD=false
DO_CTEST=false
DO_DISTRIBUTED=false
CLEAN_BUILD=false
SITE_NAME=""

# Colors for output
RED='\033[0;31m'
Expand Down Expand Up @@ -103,6 +106,10 @@ while [[ $# -gt 0 ]]; do
CLEAN_BUILD=true
shift
;;
--site)
SITE_NAME="$2"
shift 2
;;
--help|-h)
show_help
;;
Expand Down Expand Up @@ -140,7 +147,11 @@ if [ "$DO_BUILD" = true ]; then
print_header "Step 1: Building with Coverage Instrumentation"

print_info "Configuring build with coverage enabled..."
cmake --preset=debug -DWRP_CORE_ENABLE_COVERAGE=ON
cmake --preset=debug \
-DWRP_CORE_ENABLE_COVERAGE=ON \
-DWRP_CTE_ENABLE_ADIOS2_ADAPTER=OFF \
-DWRP_CTE_ENABLE_COMPRESS=OFF \
-DWRP_CORE_ENABLE_GRAY_SCOTT=OFF

print_info "Building project..."
NUM_CORES=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
Expand All @@ -165,15 +176,39 @@ if [ "$DO_CTEST" = true ]; then

cd "${BUILD_DIR}"

print_info "Running all CTest tests..."
ctest --output-on-failure

CTEST_EXIT_CODE=$?
if [ $CTEST_EXIT_CODE -eq 0 ]; then
print_success "All CTest tests passed"
if [ -n "${SITE_NAME}" ]; then
print_info "Running tests and submitting to CDash (site: ${SITE_NAME})..."
# Generate CTest dashboard script for CDash submission
cat > "${BUILD_DIR}/cdash_coverage.cmake" << EOFCMAKE
set(CTEST_SITE "${SITE_NAME}")
set(CTEST_BUILD_NAME "coverage")
set(CTEST_SOURCE_DIRECTORY "${REPO_ROOT}")
set(CTEST_BINARY_DIRECTORY "${BUILD_DIR}")
set(CTEST_DROP_METHOD "https")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=HERMES")
set(CTEST_DROP_SITE_CDASH TRUE)
set(CTEST_COVERAGE_COMMAND "gcov")
ctest_start("Experimental")
ctest_test(RETURN_VALUE test_result)
ctest_coverage()
ctest_submit()
if(NOT test_result EQUAL 0)
message("Some tests failed (exit code: \${test_result})")
endif()
EOFCMAKE
ctest -S "${BUILD_DIR}/cdash_coverage.cmake" -VV || true
print_success "CDash submission complete"
else
print_error "Some CTest tests failed (exit code: $CTEST_EXIT_CODE)"
print_warning "Continuing with coverage generation..."
print_info "Running all CTest tests..."
CTEST_EXIT_CODE=0
ctest --output-on-failure || CTEST_EXIT_CODE=$?
if [ $CTEST_EXIT_CODE -eq 0 ]; then
print_success "All CTest tests passed"
else
print_error "Some CTest tests failed (exit code: $CTEST_EXIT_CODE)"
print_warning "Continuing with coverage generation..."
fi
fi

cd "${REPO_ROOT}"
Expand Down Expand Up @@ -284,13 +319,7 @@ print_header "Step 4: Collecting and Merging Coverage Data"

cd "${BUILD_DIR}"

print_info "Capturing final coverage data with lcov (using RC file for comprehensive error handling)..."
# Create temporary lcovrc to handle all known coverage data issues
cat > lcovrc_temp << 'EOFRC'
geninfo_unexecuted_blocks = 1
geninfo_compat_libtool = 1
lcov_branch_coverage = 0
EOFRC
print_info "Capturing final coverage data with lcov..."

# Use geninfo directly with comprehensive error ignoring for all components at once
# This approach gives more accurate results than capturing from root directory
Expand All @@ -302,8 +331,6 @@ lcov --capture \
--ignore-errors graph,mismatch,negative,inconsistent,unused,empty,gcov,source \
2>&1 | grep -E "Found [0-9]+ data files|Finished" || true

rm -f lcovrc_temp

if [ ! -f coverage_combined.info ] || [ ! -s coverage_combined.info ]; then
print_error "Failed to generate coverage data"
exit 1
Expand Down
5 changes: 3 additions & 2 deletions context-assimilation-engine/test/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function(add_cae_unit_test TEST_NAME TEST_SOURCE)

# Set test environment variables
set_tests_properties(${TEST_NAME} PROPERTIES
ENVIRONMENT "CHIMAERA_WITH_RUNTIME=1;CHI_SERVER_CONF=${CMAKE_CURRENT_SOURCE_DIR}/wrp_config.yaml"
ENVIRONMENT "CHIMAERA_WITH_RUNTIME=1;CHI_SERVER_CONF=${CMAKE_CURRENT_SOURCE_DIR}/wrp_config.yaml;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/bin:$ENV{LD_LIBRARY_PATH}"
TIMEOUT 300 # 5 minute timeout
)
endfunction()
Expand Down Expand Up @@ -117,7 +117,7 @@ add_cae_unit_test(cae_range_assim

# Set smaller file size for range test to speed up CI
set_tests_properties(cae_range_assim PROPERTIES
ENVIRONMENT "CHIMAERA_WITH_RUNTIME=1;CHI_SERVER_CONF=${CMAKE_CURRENT_SOURCE_DIR}/wrp_config.yaml;TEST_FILE_SIZE=10" # 10MB instead of default
ENVIRONMENT "CHIMAERA_WITH_RUNTIME=1;CHI_SERVER_CONF=${CMAKE_CURRENT_SOURCE_DIR}/wrp_config.yaml;TEST_FILE_SIZE=10;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/bin:$ENV{LD_LIBRARY_PATH}" # 10MB instead of default
)

#------------------------------------------------------------------------------
Expand Down Expand Up @@ -198,6 +198,7 @@ set_tests_properties(
PROPERTIES
TIMEOUT 120
LABELS "coverage;comprehensive"
ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/bin:$ENV{LD_LIBRARY_PATH}"
)

#------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ TEST_CASE("CAE - File URL Parsing", "[cae][url]") {
REQUIRE(ctx.src.find("file::") == 0);

ctx.src = "file:///absolute/path/file.dat";
REQUIRE(ctx.src.find("file::") == 0);
REQUIRE(ctx.src.find("file:") == 0);

INFO("File URL parsing works correctly");
}
Expand Down
3 changes: 2 additions & 1 deletion context-exploration-engine/api/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function(add_cee_api_unit_test TEST_NAME TEST_SOURCE)

# Set test environment variables
set_tests_properties(${TEST_NAME} PROPERTIES
ENVIRONMENT "INIT_CHIMAERA=1"
ENVIRONMENT "INIT_CHIMAERA=1;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/bin:$ENV{LD_LIBRARY_PATH}"
TIMEOUT 300 # 5 minute timeout
)
endfunction()
Expand Down Expand Up @@ -82,6 +82,7 @@ set_tests_properties(
PROPERTIES
TIMEOUT 180
LABELS "cee;comprehensive;coverage"
ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/bin:$ENV{LD_LIBRARY_PATH}"
)

#------------------------------------------------------------------------------
Expand Down
12 changes: 12 additions & 0 deletions context-exploration-engine/api/test/test_context_comprehensive.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include <wrp_cae/core/constants.h>
#include <wrp_cae/core/factory/assimilation_ctx.h>
#include <wrp_cte/core/core_client.h>
#include <chimaera/bdev/bdev_tasks.h>
#include <chimaera/chimaera.h>
#include <fstream>
#include <cstdlib>
Expand Down Expand Up @@ -102,6 +103,17 @@ class CEEComprehensiveFixture {
throw std::runtime_error("CTE pool creation failed");
}

// Register a RAM storage target so PutBlob can allocate space.
// When CHI_SERVER_CONF is set, compose config already registers targets,
// but when it's absent (e.g., compute nodes), the pool has none.
auto reg_task = cte_client->AsyncRegisterTarget(
"ram::cee_test_cache",
chimaera::bdev::BdevType::kRam,
512 * 1024 * 1024, // 512 MB
chi::PoolQuery::Local(),
chi::PoolId(512, 10)); // explicit bdev pool id
reg_task.Wait();

// Initialize CAE client
WRP_CAE_CLIENT_INIT();

Expand Down
2 changes: 1 addition & 1 deletion context-runtime/include/chimaera/ipc_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ class IpcManager {
static constexpr size_t kShmMetadataOverhead = 32ULL * 1024 * 1024;

/** Multiplier for shared memory allocation to ensure space for metadata */
static constexpr float kShmAllocationMultiplier = 1.2f;
static constexpr float kShmAllocationMultiplier = 2.5f;
};

} // namespace chi
Expand Down
28 changes: 18 additions & 10 deletions context-runtime/modules/admin/test/test_compose.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,24 @@ TEST_CASE("Parse compose configuration", "[compose]") {
// Get compose config
const auto& compose_config = config_manager->GetComposeConfig();

// Verify compose section was parsed
REQUIRE(compose_config.pools_.size() == 1);

// Verify pool configuration
const auto& pool_config = compose_config.pools_[0];
REQUIRE(pool_config.mod_name_ == "chimaera_bdev");
REQUIRE(pool_config.pool_name_ == "/tmp/test_bdev.dat");
REQUIRE(pool_config.pool_id_.major_ == 200);
REQUIRE(pool_config.pool_id_.minor_ == 0);
REQUIRE(pool_config.pool_query_.IsDynamicMode());
// Verify compose section was parsed - at least 1 pool should exist
// (there may be more from server initialization)
REQUIRE(compose_config.pools_.size() >= 1);

// Find our test pool configuration (chimaera_bdev with pool_name /tmp/test_bdev.dat)
bool found_test_pool = false;
for (const auto& pool_config : compose_config.pools_) {
if (pool_config.mod_name_ == "chimaera_bdev" &&
pool_config.pool_name_ == "/tmp/test_bdev.dat") {
// Verify pool configuration
REQUIRE(pool_config.pool_id_.major_ == 200);
REQUIRE(pool_config.pool_id_.minor_ == 0);
REQUIRE(pool_config.pool_query_.IsDynamicMode());
found_test_pool = true;
break;
}
}
REQUIRE(found_test_pool);

std::cout << "Parse compose config test passed\n";
}
Expand Down
6 changes: 1 addition & 5 deletions context-runtime/src/work_orchestrator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,7 @@ void WorkOrchestrator::Finalize() {
StopWorkers();
}

// Cleanup worker threads using HSHM thread model
auto thread_model = HSHM_THREAD_MODEL;
for (auto &thread : worker_threads_) {
thread_model->Join(thread);
}
// StopWorkers already joined threads (with timeout), just clear the vectors
worker_threads_.clear();

// Clear worker containers
Expand Down
26 changes: 23 additions & 3 deletions context-runtime/test/simple_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,34 @@ class TestRegistrar {
#define INFO(message) \
std::cout << " [INFO] " << message << std::endl

// Check if a test name matches a filter (supports [tag] matching)
inline bool matches_filter(const std::string& name, const std::string& filter) {
if (filter.empty()) return true;
// If filter contains '[', extract all [tag] tokens and check each
if (filter.find('[') != std::string::npos) {
size_t pos = 0;
while (pos < filter.size()) {
size_t start = filter.find('[', pos);
if (start == std::string::npos) break;
size_t end = filter.find(']', start);
if (end == std::string::npos) break;
std::string tag = filter.substr(start, end - start + 1);
if (name.find(tag) == std::string::npos) return false;
pos = end + 1;
}
return true;
}
return name.find(filter) != std::string::npos;
}

// Main test runner with optional filter
inline int run_all_tests(const std::string& filter = "") {
const auto& tests = TestRegistry::instance().get_tests();

// Count tests that match filter
int matching_tests = 0;
for (const auto& test : tests) {
if (filter.empty() || test.first.find(filter) != std::string::npos) {
if (matches_filter(test.first, filter)) {
matching_tests++;
}
}
Expand All @@ -182,7 +202,7 @@ inline int run_all_tests(const std::string& filter = "") {

for (const auto& test : tests) {
// Skip tests that don't match filter
if (!filter.empty() && test.first.find(filter) == std::string::npos) {
if (!matches_filter(test.first, filter)) {
continue;
}

Expand Down Expand Up @@ -225,7 +245,7 @@ inline int run_all_tests(const std::string& filter = "") {
// Main TEST_CASE macro that works with string names
#define TEST_CASE(test_name, tags) \
void UNIQUE_NAME(test_func_)(); \
static SimpleTest::TestRegistrar UNIQUE_NAME(test_reg_)(test_name, UNIQUE_NAME(test_func_)); \
static SimpleTest::TestRegistrar UNIQUE_NAME(test_reg_)(std::string(test_name) + " " + std::string(tags), UNIQUE_NAME(test_func_)); \
void UNIQUE_NAME(test_func_)()

// Main function for test executable
Expand Down
Loading