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
1 change: 0 additions & 1 deletion .github/workflows/ecbundle_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ jobs:
cmake \
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type || 'Release' }} \
-DBUILD_TESTING=ON \
-DENABLE_INTEGRATION_TESTS=ON \
-DENABLE_MPI_TESTS=ON \
-DTEST_TIMEOUT=${{ github.event.inputs.test_timeout || '600' }} \
-DCMAKE_C_COMPILER=gcc \
Expand Down
37 changes: 29 additions & 8 deletions .github/workflows/fesom2_ctest_runner.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
name: FESOM2 CTest Framework (Native Runner)

# This workflow tests FESOM2 core functionality using local meshes only.
# It skips remote mesh tests to avoid external dependencies in CI.
# For full testing including remote meshes, run locally with:
# ./configure.sh ubuntu -DBUILD_TESTING=ON -DBUILD_MESHDIAG=ON -DBUILD_MESHPARTITIONER=ON

# Controls when the action will run
on:
# Triggers the workflow on push or pull request events
Expand Down Expand Up @@ -128,7 +133,8 @@ jobs:
cmake \
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type || 'Release' }} \
-DBUILD_TESTING=ON \
-DENABLE_INTEGRATION_TESTS=ON \
-DBUILD_MESHDIAG=ON \
-DBUILD_MESHPARTITIONER=ON \
-DENABLE_MPI_TESTS=ON \
-DTEST_TIMEOUT=${{ github.event.inputs.test_timeout || '600' }} \
-DCMAKE_C_COMPILER=gcc \
Expand All @@ -154,7 +160,7 @@ jobs:

echo "Build completed successfully"

# Verify executable exists
# Verify executables exist
if [ -f "bin/fesom.x" ]; then
echo "✅ FESOM2 executable created successfully"
ls -la bin/fesom.x
Expand All @@ -163,6 +169,20 @@ jobs:
find . -name "fesom.x" -type f || echo "No fesom.x found anywhere"
exit 1
fi

if [ -f "bin/fesom_meshdiag" ]; then
echo "✅ FESOM2 meshdiag executable created successfully"
ls -la bin/fesom_meshdiag
else
echo "⚠️ FESOM2 meshdiag executable not found"
fi

if [ -f "bin/fesom_meshpart" ]; then
echo "✅ FESOM2 mesh partitioner executable created successfully"
ls -la bin/fesom_meshpart
else
echo "⚠️ FESOM2 mesh partitioner executable not found"
fi

- name: List available tests
run: |
Expand Down Expand Up @@ -205,14 +225,15 @@ jobs:
echo "Running tests matching pattern: $TEST_PATTERN"
ctest $CTEST_ARGS -R "$TEST_PATTERN"
else
echo "Running selected integration tests:"
echo "- integration_full_run_mpi2"
echo "- integration_full_run_mpi8"
echo "Running core integration tests:"
echo "- integration_pi_mpi2"
echo "- integration_pi_mpi8"
echo "- integration_pi_cavity_mpi2"
echo "- integration_test_data_check"
echo "- integration_meshdiag_pi_mpi2"
echo "- meshpartitioner_partition_local_pi_mesh_4"

# Run only the specified tests using regex pattern
ctest $CTEST_ARGS -R "(integration_full_run_mpi2|integration_full_run_mpi8|integration_pi_cavity_mpi2|integration_test_data_check)"
# Run only the core local tests (skip remote tests in CI to avoid external dependencies)
ctest $CTEST_ARGS -R "(integration_pi_mpi2|integration_pi_mpi8|integration_pi_cavity_mpi2|integration_meshdiag_pi_mpi2|meshpartitioner_partition_local_pi_mesh_4)"
fi

# Capture exit code
Expand Down
195 changes: 192 additions & 3 deletions cmake/FesomTesting.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ function(update_namelist_config_with_options NAMELIST_IN NAMELIST_OUT STEP_PER_D
# Set logfile output frequency
string(REGEX REPLACE "logfile_outfreq=[0-9]+" "logfile_outfreq=${LOGFILE_OUTFREQ}" CONTENT "${CONTENT}")
# Force rotation for test geometry
string(REGEX REPLACE "force_rotation=.[a-zA-Z]." "force_rotation=${FORCE_ROTATION}" CONTENT "${CONTENT}")
string(REGEX REPLACE "force_rotation=\\.[a-zA-Z]+\\." "force_rotation=${FORCE_ROTATION}" CONTENT "${CONTENT}")
# Set cavity usage
string(REGEX REPLACE "use_cavity=.[a-zA-Z]." "use_cavity=${USE_CAVITY}" CONTENT "${CONTENT}")
string(REGEX REPLACE "use_cavity=\\.[a-zA-Z]+\\." "use_cavity=${USE_CAVITY}" CONTENT "${CONTENT}")

file(WRITE "${NAMELIST_OUT}" "${CONTENT}")
endfunction()
Expand Down Expand Up @@ -482,10 +482,15 @@ endfunction()

# Function to add a FESOM meshdiag test with custom options
function(add_fesom_meshdiag_test_with_options TEST_NAME MESH_NAME RUNID)
set(oneValueArgs NP TIMEOUT)
set(oneValueArgs NP TIMEOUT PREFIX)
set(multiValueArgs COMMAND_ARGS)
cmake_parse_arguments(FESOM_TEST "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Apply prefix if provided
if(FESOM_TEST_PREFIX)
set(TEST_NAME "${FESOM_TEST_PREFIX}_${TEST_NAME}")
endif()

# Set defaults (meshdiag requires MPI, minimum 2 processes)
if(NOT DEFINED FESOM_TEST_NP)
set(FESOM_TEST_NP 2)
Expand Down Expand Up @@ -566,3 +571,187 @@ function(add_fesom_meshdiag_test_with_options TEST_NAME MESH_NAME RUNID)

message(STATUS "Added FESOM meshdiag test: ${TEST_NAME} with mesh: ${MESH_NAME}, runid: ${RUNID}")
endfunction()

#===============================================================================
# Generic Mesh Pipeline Functions
#===============================================================================

# Function to add mesh download fixture
function(add_mesh_download_fixture MESH_NAME)
# Parse optional prefix argument
set(oneValueArgs PREFIX)
cmake_parse_arguments(DOWNLOAD_ARGS "" "${oneValueArgs}" "" ${ARGN})

if(DOWNLOAD_ARGS_PREFIX)
set(DOWNLOAD_TEST_NAME "${DOWNLOAD_ARGS_PREFIX}_download_mesh_${MESH_NAME}")
else()
set(DOWNLOAD_TEST_NAME "download_mesh_${MESH_NAME}")
endif()

add_test(
NAME ${DOWNLOAD_TEST_NAME}
COMMAND ${CMAKE_COMMAND}
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-DMESH_NAME=${MESH_NAME}
-P ${CMAKE_SOURCE_DIR}/tests/integration/mesh_download.cmake
)

set_tests_properties(${DOWNLOAD_TEST_NAME} PROPERTIES
TIMEOUT 1200 # 20 minutes for download
FIXTURES_SETUP "mesh_${MESH_NAME}"
LABELS "download_mesh"
)

message(STATUS "Added mesh download fixture: ${DOWNLOAD_TEST_NAME}")
endfunction()

# Function to add mesh partition fixture
function(add_mesh_partition_fixture MESH_NAME NUM_PROCESSES)
# Parse optional prefix argument
set(oneValueArgs PREFIX)
cmake_parse_arguments(PARTITION_ARGS "" "${oneValueArgs}" "" ${ARGN})

if(PARTITION_ARGS_PREFIX)
set(PARTITION_TEST_NAME "${PARTITION_ARGS_PREFIX}_partition_mesh_${MESH_NAME}_${NUM_PROCESSES}")
else()
set(PARTITION_TEST_NAME "partition_mesh_${MESH_NAME}_${NUM_PROCESSES}")
endif()

add_test(
NAME ${PARTITION_TEST_NAME}
COMMAND ${CMAKE_COMMAND}
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DMESH_NAME=${MESH_NAME}
-DNUM_PROCESSES=${NUM_PROCESSES}
-P ${CMAKE_SOURCE_DIR}/tests/integration/mesh_partition.cmake
)

set_tests_properties(${PARTITION_TEST_NAME} PROPERTIES
TIMEOUT 1200 # 20 minutes for partitioning
FIXTURES_SETUP "mesh_${MESH_NAME}_${NUM_PROCESSES}"
FIXTURES_REQUIRED "mesh_${MESH_NAME}"
LABELS "partition_mesh"
)

message(STATUS "Added mesh partition fixture: ${PARTITION_TEST_NAME}")
endfunction()

# Function to add complete mesh pipeline (download + multiple partitions)
function(add_mesh_pipeline MESH_NAME)
# Parse arguments
set(oneValueArgs PREFIX)
set(multiValueArgs PROCESS_COUNTS)
cmake_parse_arguments(PIPELINE_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Use remaining args as process counts if not specified
if(NOT PIPELINE_ARGS_PROCESS_COUNTS)
set(PIPELINE_ARGS_PROCESS_COUNTS ${PIPELINE_ARGS_UNPARSED_ARGUMENTS})
if(NOT PIPELINE_ARGS_PROCESS_COUNTS)
set(PIPELINE_ARGS_PROCESS_COUNTS 2 4) # Default process counts
endif()
endif()

# Add download fixture
if(PIPELINE_ARGS_PREFIX)
add_mesh_download_fixture(${MESH_NAME} PREFIX ${PIPELINE_ARGS_PREFIX})
else()
add_mesh_download_fixture(${MESH_NAME})
endif()

# Add partition fixtures for each process count
foreach(NP ${PIPELINE_ARGS_PROCESS_COUNTS})
if(PIPELINE_ARGS_PREFIX)
add_mesh_partition_fixture(${MESH_NAME} ${NP} PREFIX ${PIPELINE_ARGS_PREFIX})
else()
add_mesh_partition_fixture(${MESH_NAME} ${NP})
endif()
endforeach()

message(STATUS "Added complete mesh pipeline for '${MESH_NAME}' with process counts: ${PIPELINE_ARGS_PROCESS_COUNTS}")
endfunction()

# Enhanced function to add FESOM test with mesh pipeline integration
function(add_fesom_mesh_test TEST_NAME MESH_NAME NP)
set(options MPI_TEST)
set(oneValueArgs TIMEOUT)
set(multiValueArgs)
cmake_parse_arguments(FESOM_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Set defaults
if(NOT DEFINED FESOM_TEST_TIMEOUT)
set(FESOM_TEST_TIMEOUT 900) # 15 minutes default
endif()

# Parse mesh configuration from registry
set(MESH_REGISTRY "${CMAKE_SOURCE_DIR}/tests/mesh_registry.json")
if(EXISTS "${MESH_REGISTRY}")
file(READ "${MESH_REGISTRY}" REGISTRY_CONTENT)

# Extract mesh configuration
string(REGEX MATCH "\"${MESH_NAME}\"[^}]*\"force_rotation\"[ ]*:[ ]*([^,}]+)" ROTATION_MATCH "${REGISTRY_CONTENT}")
if(ROTATION_MATCH)
string(STRIP "${CMAKE_MATCH_1}" FORCE_ROTATION_RAW)
string(REPLACE "true" ".true." FORCE_ROTATION "${FORCE_ROTATION_RAW}")
string(REPLACE "false" ".false." FORCE_ROTATION "${FORCE_ROTATION}")
else()
set(FORCE_ROTATION ".true.") # Default
endif()

string(REGEX MATCH "\"${MESH_NAME}\"[^}]*\"use_cavity\"[ ]*:[ ]*([^,}]+)" CAVITY_MATCH "${REGISTRY_CONTENT}")
if(CAVITY_MATCH)
string(STRIP "${CMAKE_MATCH_1}" USE_CAVITY_RAW)
string(REPLACE "true" ".true." USE_CAVITY "${USE_CAVITY_RAW}")
string(REPLACE "false" ".false." USE_CAVITY "${USE_CAVITY}")
else()
set(USE_CAVITY ".false.") # Default
endif()

# Extract timing parameters
string(REGEX MATCH "\"${MESH_NAME}\"[^}]*\"step_per_day\"[ ]*:[ ]*([^,}]+)" SPD_MATCH "${REGISTRY_CONTENT}")
if(SPD_MATCH)
string(STRIP "${CMAKE_MATCH_1}" STEP_PER_DAY)
else()
set(STEP_PER_DAY "288") # Default
endif()

string(REGEX MATCH "\"${MESH_NAME}\"[^}]*\"run_length\"[ ]*:[ ]*([^,}]+)" RL_MATCH "${REGISTRY_CONTENT}")
if(RL_MATCH)
string(STRIP "${CMAKE_MATCH_1}" RUN_LENGTH)
else()
set(RUN_LENGTH "1") # Default
endif()

string(REGEX MATCH "\"${MESH_NAME}\"[^}]*\"run_length_unit\"[ ]*:[ ]*\"([^\"]+)\"" RLU_MATCH "${REGISTRY_CONTENT}")
if(RLU_MATCH)
string(STRIP "${CMAKE_MATCH_1}" RUN_LENGTH_UNIT)
else()
set(RUN_LENGTH_UNIT "s") # Default
endif()
else()
# Fallback defaults
set(FORCE_ROTATION ".true.")
set(USE_CAVITY ".false.")
set(STEP_PER_DAY "288")
set(RUN_LENGTH "1")
set(RUN_LENGTH_UNIT "s")
endif()

# Create FESOM test with appropriate configuration from registry
add_fesom_test_with_options(${TEST_NAME}
"${MESH_NAME}" "${STEP_PER_DAY}" "${RUN_LENGTH}" "${RUN_LENGTH_UNIT}" "1" "d" "10" "${FORCE_ROTATION}" "${USE_CAVITY}"
MPI_TEST
NP ${NP}
TIMEOUT ${FESOM_TEST_TIMEOUT}
)

# Add mesh pipeline dependency
set_tests_properties(${TEST_NAME} PROPERTIES
FIXTURES_REQUIRED "mesh_${MESH_NAME}_${NP}"
LABELS "mesh_simulation"
)

message(STATUS "Added FESOM mesh test: ${TEST_NAME} (mesh: ${MESH_NAME}, ${NP} processes)")
message(STATUS " Configuration: force_rotation=${FORCE_ROTATION}, use_cavity=${USE_CAVITY}")
message(STATUS " Timing: step_per_day=${STEP_PER_DAY}, run_length=${RUN_LENGTH} ${RUN_LENGTH_UNIT}")
endfunction()
33 changes: 22 additions & 11 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ if(NOT TARGET fesom)
endif()

# Testing configuration options
option(ENABLE_INTEGRATION_TESTS "Enable integration tests that run FESOM" ON)
option(ENABLE_MPI_TESTS "Enable MPI tests (requires mpiexec/mpirun)" ON)
set(TEST_TIMEOUT 600 CACHE STRING "Default timeout for tests in seconds")

Expand Down Expand Up @@ -56,26 +55,28 @@ endif()

# Print test configuration
message(STATUS "FESOM2 Testing Configuration:")
message(STATUS " Integration tests: ${ENABLE_INTEGRATION_TESTS}")
message(STATUS " MPI tests: ${ENABLE_MPI_TESTS}")
message(STATUS " Test timeout: ${TEST_TIMEOUT}s")
message(STATUS " Test data directory: ${TEST_DATA_DIR}")
message(STATUS " MPI executable: ${MPIEXEC_EXECUTABLE}")

# Add integration tests if enabled
if(ENABLE_INTEGRATION_TESTS)
add_subdirectory(integration)
endif()
# Add integration tests
add_subdirectory(integration)

# Add mesh partitioner tests
add_subdirectory(meshpartitioner)


# Add remote mesh pipeline tests
add_subdirectory(remote)

# Add unit tests (for future expansion)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/unit/CMakeLists.txt")
add_subdirectory(unit)
endif()

# Add ecbundle tests if ecbundle is available
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ecbundle/CMakeLists.txt")
add_subdirectory(ecbundle)
endif()
# Add ecbundle tests
add_subdirectory(ecbundle)

# Create a convenience target to run all tests
add_custom_target(run_tests
Expand Down Expand Up @@ -106,9 +107,19 @@ endif()
# Create target to run only meshdiag tests (if BUILD_MESHDIAG is enabled)
if(BUILD_MESHDIAG)
add_custom_target(run_meshdiag_tests
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R "meshdiag_"
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R "(meshdiag_|generate_meshdiag_)"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running FESOM2 meshdiag tests"
VERBATIM
)
endif()

# Create target to run only mesh partitioner tests (if BUILD_MESHPARTITIONER is enabled)
if(BUILD_MESHPARTITIONER)
add_custom_target(run_meshpartitioner_tests
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -L "meshpartitioner"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running FESOM2 mesh partitioner tests"
VERBATIM
)
endif()
Loading