diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 798a7efe53..ecbff43541 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -22,7 +22,8 @@ jobs: - changed-files - checks - conda-cpp-build - - conda-cpp-tests + - conda-cpp-tests-mathopt + - conda-cpp-tests-routing - java-build - java-static-build-matrix - java-static-build @@ -424,7 +425,7 @@ jobs: build-datetime: ${{ needs.build-details.outputs.build-datetime }} script: ci/build_cpp.sh matrix_type: pull-request - conda-cpp-tests: + conda-cpp-tests-mathopt: needs: [conda-cpp-build, changed-files] permissions: actions: read @@ -436,7 +437,28 @@ jobs: if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_cpp with: build_type: pull-request - script: ci/test_cpp.sh + script: ci/test_cpp_mathopt.sh + matrix_type: pull-request + secrets: + script-env-secret-1-key: CUOPT_S3_URI + script-env-secret-1-value: ${{ secrets.CUOPT_S3_URI }} + script-env-secret-2-key: CUOPT_AWS_ACCESS_KEY_ID + script-env-secret-2-value: ${{ secrets.CUOPT_AWS_ACCESS_KEY_ID }} + script-env-secret-3-key: CUOPT_AWS_SECRET_ACCESS_KEY + script-env-secret-3-value: ${{ secrets.CUOPT_AWS_SECRET_ACCESS_KEY }} + conda-cpp-tests-routing: + needs: [conda-cpp-build, changed-files] + permissions: + actions: read + contents: read + id-token: write + packages: read + pull-requests: read + uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-tests.yaml@main + if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_cpp + with: + build_type: pull-request + script: ci/test_cpp_routing.sh matrix_type: pull-request secrets: script-env-secret-1-key: CUOPT_S3_URI @@ -847,7 +869,8 @@ jobs: pr-test-summary: name: "PR test summary (non-blocking)" needs: - - conda-cpp-tests + - conda-cpp-tests-mathopt + - conda-cpp-tests-routing - conda-python-tests - wheel-tests-cuopt - wheel-tests-cuopt-server diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7af866e0e5..b7b4dae811 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -28,7 +28,7 @@ on: permissions: {} jobs: - conda-cpp-tests: + conda-cpp-tests-mathopt: permissions: actions: read contents: read @@ -41,7 +41,30 @@ jobs: branch: ${{ inputs.branch }} date: ${{ inputs.date }} sha: ${{ inputs.sha }} - script: ci/test_cpp.sh + script: ci/test_cpp_mathopt.sh + matrix_type: nightly + secrets: + script-env-secret-1-key: CUOPT_S3_URI + script-env-secret-1-value: ${{ secrets.CUOPT_S3_URI }} + script-env-secret-2-key: CUOPT_AWS_ACCESS_KEY_ID + script-env-secret-2-value: ${{ secrets.CUOPT_AWS_ACCESS_KEY_ID }} + script-env-secret-3-key: CUOPT_AWS_SECRET_ACCESS_KEY + script-env-secret-3-value: ${{ secrets.CUOPT_AWS_SECRET_ACCESS_KEY }} + + conda-cpp-tests-routing: + permissions: + actions: read + contents: read + id-token: write + packages: read + pull-requests: read + uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-tests.yaml@main + with: + build_type: ${{ inputs.build_type }} + branch: ${{ inputs.branch }} + date: ${{ inputs.date }} + sha: ${{ inputs.sha }} + script: ci/test_cpp_routing.sh matrix_type: nightly secrets: script-env-secret-1-key: CUOPT_S3_URI @@ -260,7 +283,8 @@ jobs: contents: read if: ${{ always() && inputs.build_type == 'nightly' }} needs: - - conda-cpp-tests + - conda-cpp-tests-mathopt + - conda-cpp-tests-routing - conda-python-tests - conda-java-tests - java-static-test diff --git a/ci/run_ctests.sh b/ci/run_ctests.sh index cb6662af07..68c4648001 100755 --- a/ci/run_ctests.sh +++ b/ci/run_ctests.sh @@ -14,6 +14,9 @@ # GTEST_OUTPUT - gtest XML output prefix (set by test_cpp.sh) # GTEST_MAX_RETRIES - max retries per failing test case (default: 2) # RAPIDS_TESTS_DIR - directory for test results +# CUOPT_CPP_TEST_GROUP - which binaries to run: all (default), routing +# (binaries labeled "routing" in cpp/tests) or mathopt +# (everything else, including unlabeled binaries) set -euo pipefail @@ -212,10 +215,34 @@ run_gtest_with_retry() { return 0 } +CUOPT_CPP_TEST_GROUP="${CUOPT_CPP_TEST_GROUP:-all}" +case "${CUOPT_CPP_TEST_GROUP}" in + all | routing | mathopt) ;; + *) echo "Error: invalid CUOPT_CPP_TEST_GROUP '${CUOPT_CPP_TEST_GROUP}'" >&2; exit 1 ;; +esac + +# .labels is installed next to each labeled binary (see ConfigureTest). +has_label() { + [[ -f "$1.labels" ]] && grep -qx "$2" "$1.labels" +} + +NUM_RUN=0 for gt in "${GTEST_DIR}"/*_TEST; do + is_routing=false + has_label "${gt}" routing && is_routing=true + if [[ "${CUOPT_CPP_TEST_GROUP}" == "routing" && "${is_routing}" == false ]] || + [[ "${CUOPT_CPP_TEST_GROUP}" == "mathopt" && "${is_routing}" == true ]]; then + continue + fi + NUM_RUN=$((NUM_RUN + 1)) run_gtest_with_retry "${gt}" "$@" || true done +if [ "${NUM_RUN}" -eq 0 ]; then + echo "Error: no gtest binaries selected for group '${CUOPT_CPP_TEST_GROUP}' in ${GTEST_DIR}" >&2 + OVERALL_RC=1 +fi + # Final summary so failures are easy to spot in the raw run log. # nightly_report.py also produces a structured report from the XML files, # but this prints early (before any post-test-script steps) and surfaces diff --git a/ci/test_cpp.sh b/ci/test_cpp.sh index 8f3c2c4fa7..1349358ad4 100755 --- a/ci/test_cpp.sh +++ b/ci/test_cpp.sh @@ -34,16 +34,27 @@ rapids-print-env rapids-logger "Check GPU usage" nvidia-smi -rapids-logger "Download datasets" -./datasets/linear_programming/download_pdlp_test_dataset.sh -./datasets/mip/download_miplib_test_dataset.sh -./datasets/quadratic_programming/download_qplib_test_dataset.sh +# CUOPT_CPP_TEST_GROUP: all (default), routing or mathopt; see run_ctests.sh +CUOPT_CPP_TEST_GROUP="${CUOPT_CPP_TEST_GROUP:-all}" +export CUOPT_CPP_TEST_GROUP + +# LP/MIP/QP datasets are for mathopt tests; get_test_data.sh fetches the routing datasets. +if [[ "${CUOPT_CPP_TEST_GROUP}" != "routing" ]]; then + rapids-logger "Download mathopt datasets" + ./datasets/linear_programming/download_pdlp_test_dataset.sh + ./datasets/mip/download_miplib_test_dataset.sh + ./datasets/quadratic_programming/download_qplib_test_dataset.sh +fi RAPIDS_DATASET_ROOT_DIR="$(realpath datasets)" export RAPIDS_DATASET_ROOT_DIR -pushd "${RAPIDS_DATASET_ROOT_DIR}" -./get_test_data.sh -popd + +if [[ "${CUOPT_CPP_TEST_GROUP}" != "mathopt" ]]; then + rapids-logger "Download routing datasets" + pushd "${RAPIDS_DATASET_ROOT_DIR}" + ./get_test_data.sh + popd +fi EXITCODE=0 FAILED_STEPS=() @@ -66,7 +77,10 @@ run_step_with_timeout "gtests (run_ctests.sh)" 90m "" \ rapids-logger "Generate nightly test report" source "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/utils/nightly_report_helper.sh" -generate_nightly_report "cpp" +# Separate report type per group so routing/mathopt keep separate history. +REPORT_TYPE="cpp" +[[ "${CUOPT_CPP_TEST_GROUP}" != "all" ]] && REPORT_TYPE="cpp-${CUOPT_CPP_TEST_GROUP}" +generate_nightly_report "${REPORT_TYPE}" if [ "${#FAILED_STEPS[@]}" -gt 0 ]; then EXITCODE=1 diff --git a/ci/test_cpp_mathopt.sh b/ci/test_cpp_mathopt.sh new file mode 100755 index 0000000000..6267f8e60b --- /dev/null +++ b/ci/test_cpp_mathopt.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +export CUOPT_CPP_TEST_GROUP=mathopt +exec "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/test_cpp.sh" "$@" diff --git a/ci/test_cpp_routing.sh b/ci/test_cpp_routing.sh new file mode 100755 index 0000000000..72164d713f --- /dev/null +++ b/ci/test_cpp_routing.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +export CUOPT_CPP_TEST_GROUP=routing +exec "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/test_cpp.sh" "$@" diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 76db000434..e3d4b68095 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -71,6 +71,22 @@ endif() set(CUOPT_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +# ################################################################ ------------------------------------------------------------------ +# install_test_labels(TEST_NAME label1 [label2 ...]) +# +# Installs a .labels marker next to the test binary so ci/run_ctests.sh can select +# tests by label. Use it for tests whose LABELS are set outside ConfigureTest. +function(install_test_labels TEST_NAME) + string(REPLACE ";" "\n" _labels_text "${ARGN}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.labels" "${_labels_text}\n") + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}.labels" + COMPONENT testing + DESTINATION bin/gtests/libcuopt + EXCLUDE_FROM_ALL + ) +endfunction() + # ################################################################ ------------------------------------------------------------------ # ConfigureTest(NAME source1.cu source2.cu [STATIC_LIB] [LABELS label1 label2 ...]) # @@ -126,6 +142,7 @@ function(ConfigureTest CMAKE_TEST_NAME) rapids_test_add(NAME ${CMAKE_TEST_NAME} COMMAND ${CMAKE_TEST_NAME} INSTALL_COMPONENT_SET testing) if(CT_LABELS) set_tests_properties(${CMAKE_TEST_NAME} PROPERTIES LABELS "${CT_LABELS}") + install_test_labels(${CMAKE_TEST_NAME} ${CT_LABELS}) endif() install( TARGETS ${CMAKE_TEST_NAME} diff --git a/cpp/tests/routing/grpc/CMakeLists.txt b/cpp/tests/routing/grpc/CMakeLists.txt index 98e0bd9500..764e9de051 100644 --- a/cpp/tests/routing/grpc/CMakeLists.txt +++ b/cpp/tests/routing/grpc/CMakeLists.txt @@ -67,6 +67,7 @@ endif() rapids_test_add(NAME GRPC_ROUTING_PROBLEM_MAPPER_TEST COMMAND GRPC_ROUTING_PROBLEM_MAPPER_TEST INSTALL_COMPONENT_SET testing) set_tests_properties(GRPC_ROUTING_PROBLEM_MAPPER_TEST PROPERTIES LABELS "routing") +install_test_labels(GRPC_ROUTING_PROBLEM_MAPPER_TEST routing) # Settings mapper round-trip (no running server). This mapper reads # routing::solver_settings_t, so it covers the host-only accessors that build into @@ -100,6 +101,7 @@ endif() rapids_test_add(NAME GRPC_ROUTING_SETTINGS_MAPPER_TEST COMMAND GRPC_ROUTING_SETTINGS_MAPPER_TEST INSTALL_COMPONENT_SET testing) set_tests_properties(GRPC_ROUTING_SETTINGS_MAPPER_TEST PROPERTIES LABELS "routing") +install_test_labels(GRPC_ROUTING_SETTINGS_MAPPER_TEST routing) install( TARGETS GRPC_ROUTING_SETTINGS_MAPPER_TEST