From 8852dcc8e2995ef5da1442e79c64c14e355d87aa Mon Sep 17 00:00:00 2001 From: Paul Aiyedun <53453937+paul-aiyedun@users.noreply.github.com> Date: Fri, 7 Aug 2026 18:35:50 +0000 Subject: [PATCH 1/2] Add cudf-java JAR smoke tests --- .github/workflows/pr.yaml | 988 ++---------------- java/ci/README.md | 9 + java/smoke-tests/.gitignore | 5 + java/smoke-tests/README.md | 81 ++ java/smoke-tests/bin/fetch_bundle.sh | 111 ++ java/smoke-tests/bin/run.sh | 317 ++++++ java/smoke-tests/docker/Dockerfile.cuda12 | 14 + java/smoke-tests/docker/Dockerfile.cuda13 | 14 + java/smoke-tests/pom.xml | 113 ++ .../java/ai/rapids/cudf/smoke/SanityCudf.java | 232 ++++ 10 files changed, 957 insertions(+), 927 deletions(-) create mode 100644 java/smoke-tests/.gitignore create mode 100644 java/smoke-tests/README.md create mode 100755 java/smoke-tests/bin/fetch_bundle.sh create mode 100755 java/smoke-tests/bin/run.sh create mode 100644 java/smoke-tests/docker/Dockerfile.cuda12 create mode 100644 java/smoke-tests/docker/Dockerfile.cuda13 create mode 100644 java/smoke-tests/pom.xml create mode 100644 java/smoke-tests/src/main/java/ai/rapids/cudf/smoke/SanityCudf.java diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 500f5a71636b..462f084b47f4 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,3 +1,6 @@ +# TEMPORARY: complete override of the normal PR workflow to validate cudf-java +# packaging smoke tests against a fixed RC gather artifact. +# Revert this file to the normal PR job graph once smoke validation is done. name: pr on: push: @@ -8,935 +11,66 @@ concurrency: cancel-in-progress: true permissions: {} jobs: - # Please keep pr-builder as the top job here - pr-builder: - needs: - - build-details - - check-nightly-ci - - changed-files - - checks - - cmake-tests - - conda-cpp-build - - cpp-linters - - conda-cpp-checks - - conda-cpp-tests - - conda-python-build - - conda-python-build-noarch - - conda-python-cudf-tests - - conda-python-other-tests - - conda-java-tests - - conda-notebook-tests - - docs-build - - publish-api-docs - - wheel-build-libcudf - - wheel-build-libcudf-streaming - - wheel-build-cudf-streaming - - wheel-tests-cudf-streaming - - wheel-build-pylibcudf - - wheel-build-cudf - - wheel-tests-cudf - - wheel-build-cudf-polars - - wheel-tests-cudf-polars - - cudf-polars-polars-tests - - wheel-build-dask-cudf - - wheel-tests-dask-cudf - - devcontainer - - unit-tests-cudf-pandas - - pandas-tests - - narwhals-tests - - telemetry-setup - - third-party-integration-tests-cudf-pandas - uses: rapidsai/shared-workflows/.github/workflows/pr-builder.yaml@main - permissions: - contents: read - if: always() - with: - needs: ${{ toJSON(needs) }} - telemetry-setup: - permissions: - id-token: write - continue-on-error: true - runs-on: ubuntu-latest - env: - OTEL_SERVICE_NAME: 'pr-cudf' - steps: - - name: Telemetry setup - if: ${{ vars.TELEMETRY_ENABLED == 'true' }} - uses: rapidsai/shared-actions/telemetry-dispatch-stash-base-env-vars@main - build-details: - uses: rapidsai/shared-workflows/.github/workflows/compute-build-details.yaml@main - check-nightly-ci: - runs-on: ubuntu-latest + # TEMPORARY: smoke test RC artifact 8984957232 on amd64/arm64 × CUDA 12/13. + # Runs on the bare GPU runner (docker available) so run.sh can docker-run smoke images. + java-smoke-tests: + strategy: + fail-fast: false + matrix: + include: + - { cuda_major: "12", runner: "linux-amd64-gpu-l4-latest-1" } + - { cuda_major: "13", runner: "linux-amd64-gpu-l4-latest-1" } + - { cuda_major: "12", runner: "linux-arm64-gpu-l4-latest-1" } + - { cuda_major: "13", runner: "linux-arm64-gpu-l4-latest-1" } + runs-on: ${{ matrix.runner }} permissions: actions: read - id-token: write + contents: read env: - GH_TOKEN: ${{ github.token }} + # Fixed RC Maven-central-style bundle (run 31146897853 / artifact 8984957232). + # Name: maven-central-bundle-cudf-26.08.0-ff5b362d7c06ae5837fd7a7337e2ae20895f324d + CUDF_SMOKE_ARTIFACT_RUN_ID: "31146897853" + CUDF_SMOKE_ARTIFACT_ID: "8984957232" + CUDF_SMOKE_MAVEN_REPO: ${{ github.workspace }}/maven-repo-smoke steps: - - name: Get PR Info - id: get-pr-info - uses: nv-gha-runners/get-pr-info@090577647b8ddc4e06e809e264f7881650ecdccf # main - - name: Check if nightly CI is passing - uses: rapidsai/shared-actions/check_nightly_success/dispatch@main + - name: Checkout code repo + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: - repo: ${{ github.repository }} - target-branch: ${{ fromJSON(steps.get-pr-info.outputs.pr-info).base.ref }} - max-days-without-success: 14 - changed-files: - permissions: - actions: read - contents: read - packages: read - pull-requests: read - needs: telemetry-setup - uses: rapidsai/shared-workflows/.github/workflows/changed-files.yaml@main - with: - files_yaml: | - build_docs: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.clang-format' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!ci/build_wheel*.sh' - - '!ci/check_style.sh' - - '!ci/discover_libcudf_tests.sh' - - '!ci/release/update-version.sh' - - '!ci/run_*.sh' - - '!ci/test_*.sh' - - '!ci/validate_wheel.sh' - - '!codecov.yml' - - '!SECURITY.md' - test_cpp: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!CONTRIBUTING.md' - - '!README.md' - - '!SECURITY.md' - - '!ci/cudf_pandas_scripts/**' - - '!ci/build_docs.sh' - - '!ci/build_python*.sh' - - '!ci/build_wheel*.sh' - - '!ci/check_style.sh' - - '!ci/cudf_pandas_scripts/**' - - '!ci/release/update-version.sh' - - '!ci/test_python*.sh' - - '!ci/test_wheel*.sh' - - '!ci/validate_wheel.sh' - - '!docs/**' - - '!img/**' - - '!java/**' - - '!notebooks/**' - - '!python/**' - test_cudf_pandas: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.clang-format' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!CONTRIBUTING.md' - - '!README.md' - - '!SECURITY.md' - - '!ci/release/update-version.sh' - - '!ci/test_java.sh' - - '!ci/validate_wheel.sh' - - '!docs/**' - - '!img/**' - - '!java/**' - - '!notebooks/**' - test_java: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.clang-format' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!CONTRIBUTING.md' - - '!README.md' - - '!SECURITY.md' - - '!ci/build_docs.sh' - - '!ci/build_wheel*.sh' - - '!ci/check_style.sh' - - '!ci/cudf_pandas_scripts/**' - - '!ci/release/update-version.sh' - - '!ci/test_wheel*.sh' - - '!ci/validate_wheel.sh' - - '!ci/release/update-version.sh' - - '!codecov.yml' - - '!docs/**' - - '!img/**' - - '!notebooks/**' - - '!python/**' - test_notebooks: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.clang-format' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!CONTRIBUTING.md' - - '!README.md' - - '!SECURITY.md' - - '!ci/build_wheel*.sh' - - '!ci/cudf_pandas_scripts/**' - - '!ci/release/update-version.sh' - - '!ci/test_wheel*.sh' - - '!ci/validate_wheel.sh' - - '!codecov.yml' - - '!java/**' - test_python_conda: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.clang-format' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!CONTRIBUTING.md' - - '!README.md' - - '!SECURITY.md' - - '!ci/build_docs.sh' - - '!ci/build_wheel*.sh' - - '!ci/check_style.sh' - - '!ci/cudf_pandas_scripts/**' - - '!ci/release/update-version.sh' - - '!ci/test_java.sh' - - '!ci/test_wheel*.sh' - - '!ci/validate_wheel.sh' - - '!docs/**' - - '!img/**' - - '!java/**' - - '!notebooks/**' - test_python_wheels: - - '**' - - '!**/REVIEW_GUIDELINES.md' - - '!.coderabbit.yaml' - - '!.clang-format' - - '!.devcontainer/**' - - '!.github/CODEOWNERS' - - '!.github/ISSUE_TEMPLATE/**' - - '!.github/PULL_REQUEST_TEMPLATE.md' - - '!.github/copy-pr-bot.yaml' - - '!.github/labeler.yml' - - '!.github/ops-bot.yaml' - - '!.github/release.yml' - - '!.github/workflows/auto-assign.yml' - - '!.github/workflows/build.yaml' - - '!.github/workflows/issue-release-scheduled.yml' - - '!.github/workflows/labeler.yml' - - '!.github/workflows/pr_issue_status_automation.yml' - - '!.github/workflows/test.yaml' - - '!.github/workflows/trigger-breaking-change-alert.yaml' - - '!.pre-commit-config.yaml' - - '!.yamllint.yaml' - - '!CONTRIBUTING.md' - - '!README.md' - - '!SECURITY.md' - - '!ci/build_cpp.sh' - - '!ci/build_docs.sh' - - '!ci/build_python_noarch.sh' - - '!ci/build_python.sh' - - '!ci/check-style.sh' - - '!ci/cudf_pandas_scripts/**' - - '!ci/release/update-version.sh' - - '!ci/test_cpp.sh' - - '!ci/test_cpp_common.sh' - - '!ci/test_cpp_memcheck.sh' - - '!ci/test_java.sh' - - '!ci/test_notebooks.sh' - - '!ci/test_python_common.sh' - - '!ci/test_python_cudf.sh' - - '!ci/test_python_other.sh' - - '!codecov.yml' - - '!conda/**' - - '!docs/**' - - '!img/**' - - '!java/**' - - '!notebooks/**' - not_cudf_polars: - - '**' - - '!python/cudf_polars/**' - neither_cudf_polars_nor_dask_cudf: - - '**' - - '!python/cudf_polars/**' - - '!python/dask_cudf/**' - neither_cudf_nor_dask_cudf: - - '**' - - '!python/cudf/**' - - '!python/dask_cudf/**' - neither_cpp_nor_cudf_polars_nor_dask_cudf: - - '**' - - '!cpp/**' - - '!python/cudf_polars/**' - - '!python/dask_cudf/**' - checks: - permissions: - contents: read - needs: telemetry-setup - uses: rapidsai/shared-workflows/.github/workflows/checks.yaml@main - with: - enable_check_generated_files: false - ignored_pr_jobs: "telemetry-summarize spark-rapids-jni cuml-compat-tests" - conda-cpp-build: - needs: [build-details, checks] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-build.yaml@main - with: - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu16 - script: ci/build_cpp.sh - cmake-tests: - needs: checks - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - with: - build_type: pull-request - node_type: cpu16 - arch: "amd64" - container_image: "rapidsai/ci-conda:26.10-latest" - script: "ci/test_cmake.sh" - cpp-linters: - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - needs: checks - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - with: - build_type: pull-request - script: "ci/cpp_linters.sh" - conda-cpp-checks: - needs: conda-cpp-build - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - uses: rapidsai/shared-workflows/.github/workflows/conda-cpp-post-build-checks.yaml@main - with: - build_type: pull-request - package_name: libcudf - conda-cpp-tests: - needs: [conda-cpp-build, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - 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.sh - # https://github.com/rapidsai/cudf/issues/23498 - matrix_filter: map(select(.GPU != "gb300" and .GPU != "gh200")) - conda-python-build: - needs: [build-details, conda-cpp-build] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@main - with: - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - script: ci/build_python.sh - # Build a conda package for each CUDA x ARCH x minimum supported Python version - matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) - conda-python-build-noarch: - needs: [build-details, conda-cpp-build, conda-python-build] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/conda-python-build.yaml@main - with: - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - script: ci/build_python_noarch.sh - pure-conda: cuda_major - conda-python-cudf-tests: - needs: [conda-python-build, conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_conda && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cudf_polars_nor_dask_cudf - with: - build_type: pull-request - script: "ci/test_python_cudf.sh" - # https://github.com/rapidsai/cudf/issues/23498 - matrix_filter: map(select(.GPU != "gb300" and .GPU != "gh200")) - conda-python-other-tests: - # Tests for dask_cudf, cudf_polars, custreamz, cudf_kafka are separated for CI parallelism - needs: [conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/conda-python-tests.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_conda - with: - build_type: pull-request - # https://github.com/rapidsai/cudf/pull/22381/changes#r3196736965 - container-options: "--cap-add CAP_SYS_PTRACE --shm-size=8g --ulimit=nofile=1000000:1000000" - script: "ci/test_python_other.sh" - # https://github.com/rapidsai/cudf/issues/23498 - matrix_filter: map(select(.GPU != "gb300" and .GPU != "gh200")) - conda-java-tests: - needs: [conda-cpp-build, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_java - with: - build_type: pull-request - node_type: "gpu-l4-latest-1" - arch: "amd64" - container_image: "rapidsai/ci-conda:26.10-latest" - script: "ci/test_java.sh" - conda-notebook-tests: - needs: [conda-python-build, conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_notebooks - with: - build_type: pull-request - node_type: "gpu-l4-latest-1" - arch: "amd64" - container_image: "rapidsai/ci-conda:26.10-latest" - script: "ci/test_notebooks.sh" - docs-build: - needs: [conda-python-build, conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).build_docs - with: - build_type: pull-request - node_type: "gpu-l4-latest-1" - arch: "amd64" - container_image: "rapidsai/ci-conda:26.10-latest" - script: "ci/build_docs.sh" - publish-api-docs: - needs: [docs-build] - permissions: - contents: read - id-token: write - secrets: - akamai-access-token: ${{ secrets.NVIDIA_DOCS_AKAMAI_ACCESS_TOKEN }} - akamai-client-token: ${{ secrets.NVIDIA_DOCS_AKAMAI_CLIENT_TOKEN }} - akamai-client-secret: ${{ secrets.NVIDIA_DOCS_AKAMAI_CLIENT_SECRET }} - akamai-emails-to-notify: ${{ secrets.NVIDIA_DOCS_AKAMAI_EMAILS_TO_NOTIFY }} - akamai-host: ${{ secrets.NVIDIA_DOCS_AKAMAI_HOST }} - target-aws-access-key-id: ${{ secrets.NVIDIA_DOCS_AWS_ACCESS_KEY_ID }} - target-aws-region: ${{ secrets.NVIDIA_DOCS_AWS_REGION }} - target-aws-secret-access-key: ${{ secrets.NVIDIA_DOCS_AWS_SECRET_ACCESS_KEY }} - target-s3-bucket: ${{ secrets.NVIDIA_DOCS_S3_BUCKET }} - uses: rapidsai/shared-workflows/.github/workflows/publish-api-docs.yaml@main - with: - docs-projects: cudf,libcudf - dry-run: true - version-map: '{"26.04": "legacy", "26.06": "stable"}' - wheel-build-libcudf: - needs: [build-details, checks] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - # build for every combination of arch and CUDA version, but only for the latest Python - matrix_filter: group_by([.ARCH, (.CUDA_VER|split(".")|map(tonumber)|.[0])]) | map(max_by(.PY_VER|split(".")|map(tonumber))) - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu16 - script: "ci/build_wheel_libcudf.sh" - package-name: libcudf - package-type: cpp - wheel-build-libcudf-streaming: - needs: [build-details, checks, wheel-build-libcudf] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - # build for every combination of arch and CUDA version, but only for the latest Python - matrix_filter: group_by([.ARCH, (.CUDA_VER|split(".")|map(tonumber)|.[0])]) | map(max_by(.PY_VER|split(".")|map(tonumber))) - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu16 - script: "ci/build_wheel_libcudf_streaming.sh" - package-name: libcudf_streaming - package-type: cpp - wheel-build-cudf-streaming: - needs: [build-details, checks, wheel-build-libcudf-streaming, wheel-build-pylibcudf] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - # Build a wheel for each CUDA x ARCH x minimum supported Python version - matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu16 - script: "ci/build_wheel_cudf_streaming.sh" - package-name: cudf_streaming - package-type: python - wheel-tests-cudf-streaming: - needs: [wheel-build-cudf-streaming, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels - with: - build_type: pull-request - script: ci/test_wheel_cudf_streaming.sh - # https://github.com/rapidsai/cudf/issues/23498 - matrix_filter: map(select(.GPU != "gb300" and .GPU != "gh200")) - wheel-build-pylibcudf: - needs: [build-details, checks, wheel-build-libcudf] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu8 - script: "ci/build_wheel_pylibcudf.sh" - package-name: pylibcudf - package-type: python - # Build a wheel for each CUDA x ARCH x minimum supported Python version - matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) - wheel-build-cudf: - needs: [build-details, wheel-build-pylibcudf] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu8 - script: "ci/build_wheel_cudf.sh" - package-name: cudf - package-type: python - # Build a wheel for each CUDA x ARCH x minimum supported Python version - matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) - wheel-tests-cudf: - needs: [wheel-build-cudf, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cudf_polars_nor_dask_cudf - with: - build_type: pull-request - script: ci/test_wheel_cudf.sh - # https://github.com/rapidsai/cudf/issues/23498 - matrix_filter: map(select(.GPU != "gb300" and .GPU != "gh200")) - wheel-build-cudf-polars: - needs: [build-details, wheel-build-pylibcudf] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - # This selects "ARCH=amd64 + the latest supported Python + CUDA". - matrix_filter: map(select(.ARCH == "amd64")) | group_by(.CUDA_VER|split(".")|map(tonumber)|.[0]) | map(max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))])) - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu8 - script: "ci/build_wheel_cudf_polars.sh" - package-name: cudf_polars - package-type: python - pure-wheel: true - wheel-tests-cudf-polars: - needs: [wheel-build-cudf-polars, wheel-build-cudf-streaming, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cudf_nor_dask_cudf - with: - # This selects "ARCH=amd64 + the latest supported Python + CUDA". - matrix_filter: map(select(.ARCH == "amd64")) | group_by(.CUDA_VER|split(".")|map(tonumber)|.[0]) | map(max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))])) - build_type: pull-request - container-options: "--cap-add CAP_SYS_PTRACE --shm-size=8g --ulimit=nofile=1000000:1000000" - script: "env POLARS_VERSIONS=endpoints ci/test_wheel_cudf_polars.sh" - cudf-polars-polars-tests: - needs: [wheel-build-cudf-polars, wheel-build-cudf-streaming, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cudf_nor_dask_cudf - with: - # This selects "ARCH=amd64 + the latest supported Python + CUDA". - matrix_filter: map(select(.ARCH == "amd64")) | group_by(.CUDA_VER|split(".")|map(tonumber)|.[0]) | map(max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))])) - build_type: pull-request - script: "ci/test_cudf_polars_polars_tests.sh" - wheel-build-dask-cudf: - needs: [build-details, wheel-build-cudf] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-build.yaml@main - with: - # This selects "ARCH=amd64 + the latest supported Python + CUDA". - matrix_filter: map(select(.ARCH == "amd64")) | group_by(.CUDA_VER|split(".")|map(tonumber)|.[0]) | map(max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))])) - build_type: pull-request - build-datetime: ${{ needs.build-details.outputs.build-datetime }} - node_type: cpu8 - script: "ci/build_wheel_dask_cudf.sh" - package-name: dask_cudf - package-type: python - pure-wheel: true - wheel-tests-dask-cudf: - needs: [wheel-build-dask-cudf, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels && fromJSON(needs.changed-files.outputs.changed_file_groups).not_cudf_polars - with: - # This selects "ARCH=amd64 + the latest supported Python + CUDA". - matrix_filter: map(select(.ARCH == "amd64")) | group_by(.CUDA_VER|split(".")|map(tonumber)|.[0]) | map(max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))])) - build_type: pull-request - script: ci/test_wheel_dask_cudf.sh - # build cudf with benchmarks but disable for cudf_streaming since we can't use MPI/UCX in wheel-based builds - devcontainer: - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - needs: telemetry-setup - uses: rapidsai/shared-workflows/.github/workflows/build-in-devcontainer.yaml@main - with: - arch: '["amd64", "arm64"]' - cuda: '["13.3"]' - node_type: "cpu8" - timeout-minutes: 90 - env: | - SCCACHE_DIST_MAX_RETRIES=inf - SCCACHE_SERVER_LOG=sccache=debug - SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE=false - build_command: | - sccache --zero-stats; - build-all -j0 --verbose -DBUILD_BENCHMARKS=ON 2>&1 | tee telemetry-artifacts/build.log; - sccache --show-adv-stats | tee telemetry-artifacts/sccache-stats.txt; - unit-tests-cudf-pandas: - needs: [wheel-build-cudf, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/wheels-test.yaml@main - if: (fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels || fromJSON(needs.changed-files.outputs.changed_file_groups).test_cudf_pandas) && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cudf_polars_nor_dask_cudf - with: - # This selects the latest supported Python + CUDA minor versions for each ARCH/CUDA major version combo - # Filter out GB300 due to https://github.com/rapidsai/cudf/issues/23498 - matrix_filter: group_by([(.ARCH), (.CUDA_VER|split(".")|map(tonumber)|.[0])]) | map(max_by([(.PY_VER|split(".")|map(tonumber)), (.CUDA_VER|split(".")|map(tonumber))])) | map(select(.GPU != "gb300" and .GPU != "gh200")) - build_type: pull-request - script: ci/cudf_pandas_scripts/run_tests.sh - third-party-integration-tests-cudf-pandas: - needs: [conda-python-build, conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_conda && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cpp_nor_cudf_polars_nor_dask_cudf - with: - build_type: pull-request - branch: ${{ inputs.branch }} - date: ${{ inputs.date }} - sha: ${{ inputs.sha }} - node_type: "gpu-l4-latest-1" - continue-on-error: true - container_image: "rapidsai/ci-conda:26.10-latest" - script: | - ci/cudf_pandas_scripts/third-party-integration/test.sh python/cudf/cudf_pandas_tests/third_party_integration_tests/dependencies.yaml - cuml-compat-tests: - needs: [conda-python-build, conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_conda && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cudf_polars_nor_dask_cudf - with: - build_type: pull-request - branch: ${{ inputs.branch }} - date: ${{ inputs.date }} - sha: ${{ inputs.sha }} - node_type: "gpu-l4-latest-1" - continue-on-error: true - container_image: "rapidsai/ci-conda:26.10-latest" - script: "ci/test_cuml_compat.sh" - pandas-tests: - # run the Pandas unit tests using PR branch - needs: [wheel-build-cudf, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_wheels && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cpp_nor_cudf_polars_nor_dask_cudf - with: - build_type: pull-request - branch: ${{ inputs.branch }} - date: ${{ inputs.date }} - sha: ${{ inputs.sha }} - node_type: "gpu-l4-latest-1" - container_image: "rapidsai/citestwheel:26.10-latest" - script: ci/cudf_pandas_scripts/pandas-tests/run.sh pr - narwhals-tests: - needs: [conda-python-build, conda-python-build-noarch, changed-files] - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - secrets: inherit # zizmor: ignore[secrets-inherit] - uses: rapidsai/shared-workflows/.github/workflows/custom-job.yaml@main - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_python_conda && fromJSON(needs.changed-files.outputs.changed_file_groups).neither_cpp_nor_cudf_polars_nor_dask_cudf - with: - build_type: pull-request - branch: ${{ inputs.branch }} - date: ${{ inputs.date }} - sha: ${{ inputs.sha }} - node_type: "gpu-l4-latest-1" - container_image: "rapidsai/ci-conda:26.10-latest" - script: ci/test_narwhals.sh - spark-rapids-jni: - needs: changed-files - permissions: - actions: read - contents: read - id-token: write - packages: read - pull-requests: read - uses: ./.github/workflows/spark-rapids-jni.yaml - if: fromJSON(needs.changed-files.outputs.changed_file_groups).test_java - telemetry-summarize: - # This job must use a self-hosted runner to record telemetry traces. - runs-on: linux-amd64-cpu4 - permissions: - actions: write - needs: pr-builder - if: ${{ vars.TELEMETRY_ENABLED == 'true' && !cancelled() }} - continue-on-error: true - steps: - - name: Telemetry summarize - uses: rapidsai/shared-actions/telemetry-dispatch-summarize@main - env: - GH_TOKEN: ${{ github.token }} + fetch-depth: 0 + persist-credentials: false + - name: Download RC Maven bundle + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + artifact-ids: ${{ env.CUDF_SMOKE_ARTIFACT_ID }} + repository: rapidsai/cudf + run-id: ${{ env.CUDF_SMOKE_ARTIFACT_RUN_ID }} + github-token: ${{ github.token }} + path: ${{ env.CUDF_SMOKE_MAVEN_REPO }} + merge-multiple: true + - name: Locate Maven-repo root + run: | + if [[ -d "${CUDF_SMOKE_MAVEN_REPO}/ai/rapids/cudf" ]]; then + echo "CUDF_SMOKE_MAVEN_REPO_DIR=${CUDF_SMOKE_MAVEN_REPO}" >> "${GITHUB_ENV}" + exit 0 + fi + # download-artifact may nest under the artifact name directory. + found="$(find "${CUDF_SMOKE_MAVEN_REPO}" -type d -path '*/ai/rapids/cudf' | head -n 1 || true)" + if [[ -z "${found}" ]]; then + echo "ERROR: no ai/rapids/cudf/ under ${CUDF_SMOKE_MAVEN_REPO}" >&2 + find "${CUDF_SMOKE_MAVEN_REPO}" -maxdepth 3 -type d >&2 || true + exit 1 + fi + repo_dir="$(cd "${found}/../../.." && pwd)" + echo "CUDF_SMOKE_MAVEN_REPO_DIR=${repo_dir}" >> "${GITHUB_ENV}" + echo "Using Maven-repo root: ${repo_dir}" + - name: Ensure docker + run: | + if ! command -v docker >/dev/null 2>&1; then + echo "ERROR: docker is required (run.sh always uses Docker)" >&2 + exit 1 + fi + - name: Run cudf-java smoke tests + run: | + ./java/smoke-tests/bin/run.sh \ + --maven-repo-dir "${CUDF_SMOKE_MAVEN_REPO_DIR}" \ + --cuda-version "${{ matrix.cuda_major }}" diff --git a/java/ci/README.md b/java/ci/README.md index 49ab3b6074ec..186a28fd2d5a 100644 --- a/java/ci/README.md +++ b/java/ci/README.md @@ -90,6 +90,15 @@ per-entry artifact. The separate `java-gather` job downloads them (with `merge-multiple: true`, so all subdirs land in a single parent dir), runs Step 3, and uploads the combined `cudf_java_maven_repo` artifact. +### Step 4 - Smoke tests (optional, local) + +After assembling a Maven-repo tree, run the packaging smoke suite under +[`java/smoke-tests/`](../smoke-tests/README.md): + +```bash +./java/smoke-tests/bin/run.sh --maven-repo-dir /tmp/maven-repo +``` + ## Legacy: manual Dockerfile.rocky build (obsolete) > The `java/ci/Dockerfile.rocky` + `java/ci/build-in-docker.sh` flow below is the diff --git a/java/smoke-tests/.gitignore b/java/smoke-tests/.gitignore new file mode 100644 index 000000000000..4a6c025d59fa --- /dev/null +++ b/java/smoke-tests/.gitignore @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. +# SPDX-License-Identifier: Apache-2.0 + +.cache/ +target/ diff --git a/java/smoke-tests/README.md b/java/smoke-tests/README.md new file mode 100644 index 000000000000..d30cfaeaf1b3 --- /dev/null +++ b/java/smoke-tests/README.md @@ -0,0 +1,81 @@ +# cudf-java smoke tests + +Smoke published `ai.rapids:cudf` classifier JARs under a Maven Central-style +classpath (cudf + slf4j only). + +## Quick start + +Exactly one source mode is required. + +```bash +# Local gather tree (must contain ai/rapids/cudf/) +./java/smoke-tests/bin/run.sh --maven-repo-dir /tmp/cudf-java-build/maven-repo + +# GitHub Actions gather artifact +./java/smoke-tests/bin/run.sh \ + --artifact-url 'https://github.com/rapidsai/cudf/actions/runs//artifacts/' + +# Installed into ~/.m2 +./java/smoke-tests/bin/run.sh --use-maven-home + +# Maven Central release (version required) +./java/smoke-tests/bin/run.sh --use-maven-central --version 25.12.0 +``` + +Narrow to one CUDA major: + +```bash +./java/smoke-tests/bin/run.sh --maven-repo-dir /tmp/maven-repo --cuda-version 12 +``` + +## Source modes + +| Mode | Flag | +|---|---| +| GitHub Actions artifact | `--artifact-url URL` | +| Local Maven-repo tree | `--maven-repo-dir DIR` | +| `~/.m2/repository` | `--use-maven-home` | +| Maven Central | `--use-maven-central` (requires `--version`) | + +Shared options: + +| Option | Meaning | +|---|---| +| `--version VER` | Pin `ai.rapids:cudf` version. Required for Central. For other modes, if omitted, exactly one version directory must exist under `ai/rapids/cudf/`. | +| `--cuda-version 12\|13` | Narrow classifiers to this CUDA major | + +## Classifier selection + +Without `--cuda-version`, by host arch: + +- `x86_64`: `unclassified`, `cuda12`, `cuda13` +- `aarch64`: `cuda12-arm64`, `cuda13-arm64` + +With `--cuda-version N`: + +- `x86_64` + 12: `unclassified`, `cuda12` +- `x86_64` + 13: `cuda13` +- `aarch64` + N: `cudaN-arm64` + +Missing JARs are warned and skipped. The run fails if no classifier is actually smoke tested, or if any smoke-tested classifier fails. + +After each classifier run, `run.sh` also requires the native `CUDF_LOG_WARN` from +`parquetChunkedLoggerSmoke` (`Chunked Parquet reader: a chunk_read_limit`) in the +captured smoke log under `.cache/logs/`. + +## Artifact downloads + +`--artifact-url` uses [`bin/fetch_bundle.sh`](bin/fetch_bundle.sh) (requires authenticated `gh`). +Downloads land at: + +```text +java/smoke-tests/.cache/downloads/runs//artifacts// +``` + +(or under `$CUDF_JAVA_SMOKE_OUTPUT_DIR`). If that destination already exists and +contains `ai/rapids/cudf/`, the fetch warns and reuses it. + +## Docker images + +`docker/Dockerfile.cuda{12,13}` (Ubuntu 24.04 CUDA runtime + OpenJDK 17 + Maven). +Built on first use; rebuild with `docker build` / `docker rmi` if the Dockerfile changes. diff --git a/java/smoke-tests/bin/fetch_bundle.sh b/java/smoke-tests/bin/fetch_bundle.sh new file mode 100755 index 000000000000..00ea0f533df1 --- /dev/null +++ b/java/smoke-tests/bin/fetch_bundle.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Download a java-gather GitHub Actions artifact into: +# /runs//artifacts// +# Default : java/smoke-tests/.cache/downloads + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SMOKE_TESTS_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +ARTIFACT_URL="" +OUTPUT_DIR="${CUDF_JAVA_SMOKE_OUTPUT_DIR:-${SMOKE_TESTS_ROOT}/.cache/downloads}" + +info() { printf '==> %s\n' "$*" >&2; } +warn() { printf 'WARNING: %s\n' "$*" >&2; } +die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; } + +require_value() { + local flag="$1" + local value="${2:-}" + if [[ -z "${value}" ]]; then + die "${flag} requires a value" + fi +} + +print_help() { + cat << EOF +Usage: $(basename "$0") --artifact-url [--output-dir DIR] + +Download the cudf_java_maven_repo GitHub Actions artifact into: + /runs//artifacts// + + --output-dir DIR Default: ${SMOKE_TESTS_ROOT}/.cache/downloads + (or \$CUDF_JAVA_SMOKE_OUTPUT_DIR) + +Requires gh. If the destination already exists and looks valid, warns and reuses it. +EOF +} + +main() { + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) print_help; exit 0 ;; + --artifact-url) + require_value "$1" "${2:-}" + ARTIFACT_URL="$2" + shift 2 + ;; + --output-dir) + require_value "$1" "${2:-}" + OUTPUT_DIR="$2" + shift 2 + ;; + *) die "Unknown argument: $1 (try --help)" ;; + esac + done + + if [[ -z "${ARTIFACT_URL}" ]]; then + die "--artifact-url is required (try --help)" + fi + if ! command -v gh >/dev/null 2>&1; then + die "'gh' (GitHub CLI) is required" + fi + if ! command -v unzip >/dev/null 2>&1; then + die "'unzip' is required" + fi + + local repo run_id artifact_id + if [[ "${ARTIFACT_URL}" =~ github\.com/([^/]+/[^/]+)/actions/runs/([A-Za-z0-9_]+)/artifacts/([A-Za-z0-9_]+)/?$ ]]; then + repo="${BASH_REMATCH[1]}" + run_id="${BASH_REMATCH[2]}" + artifact_id="${BASH_REMATCH[3]}" + else + die "Could not parse artifact URL: ${ARTIFACT_URL}" + fi + + local dest="${OUTPUT_DIR}/runs/${run_id}/artifacts/${artifact_id}" + if [[ -d "${dest}/ai/rapids/cudf" ]]; then + warn "Destination already exists; reusing: ${dest}" + printf '%s\n' "${dest}" + return 0 + fi + if [[ -e "${dest}" ]]; then + die "Destination exists but is incomplete (no ai/rapids/cudf/): ${dest}" + fi + + mkdir -p "${dest}" + info "Downloading artifact ${artifact_id} from ${repo} run ${run_id}" + gh api \ + -H "Accept: application/vnd.github+json" \ + "/repos/${repo}/actions/artifacts/${artifact_id}/zip" \ + > "${dest}/artifact.zip" + unzip -q -o "${dest}/artifact.zip" -d "${dest}" + + if [[ -d "${dest}/cudf_java_maven_repo/ai" ]]; then + mv "${dest}/cudf_java_maven_repo/ai" "${dest}/" + rm -rf "${dest:?}/cudf_java_maven_repo" + fi + if [[ ! -d "${dest}/ai/rapids/cudf" ]]; then + die "No ai/rapids/cudf/ under ${dest} after download" + fi + + printf 'artifact-url:%s\n' "${ARTIFACT_URL}" > "${dest}/.source" + info "Destination: ${dest}" + printf '%s\n' "${dest}" +} + +main "$@" diff --git a/java/smoke-tests/bin/run.sh b/java/smoke-tests/bin/run.sh new file mode 100755 index 000000000000..220870eb7046 --- /dev/null +++ b/java/smoke-tests/bin/run.sh @@ -0,0 +1,317 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Smoke-test cudf-java classifier JARs (cudf + slf4j classpath) in Docker. +# +# Exactly one source mode: +# --artifact-url URL | --maven-repo-dir DIR | --use-maven-home | --use-maven-central + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SMOKE_TESTS_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +CACHE_DIR="${SMOKE_TESTS_ROOT}/.cache" + +MODE="" +MAVEN_REPO="" +VERSION="" +ARTIFACT_URL="" +CUDA_VERSION="" +USE_CENTRAL=0 + +PARQUET_WARN_NEEDLE='Chunked Parquet reader: a chunk_read_limit' + +info() { printf '==> %s\n' "$*" >&2; } +warn() { printf 'WARNING: %s\n' "$*" >&2; } +die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; } + +require_value() { + local flag="$1" + local value="${2:-}" + if [[ -z "${value}" ]]; then + die "${flag} requires a value" + fi +} + +set_mode() { + local next="$1" + if [[ -n "${MODE}" ]]; then + die "Conflicting source modes: already using --${MODE}, cannot also use --${next}" + fi + MODE="${next}" +} + +print_help() { + cat << EOF +Usage: $(basename "$0") --artifact-url URL [options] + $(basename "$0") --maven-repo-dir DIR [options] + $(basename "$0") --use-maven-home [options] + $(basename "$0") --use-maven-central --version VER [options] + +Always runs smoke tests in Docker (Ubuntu 24.04 CUDA runtime + JDK 17 + Maven). + +Source modes (exactly one required): + --artifact-url URL Fetch gather artifact via fetch_bundle.sh, then test + --maven-repo-dir DIR Local Maven tree (must contain ai/rapids/cudf/) + --use-maven-home Use ~/.m2/repository + --use-maven-central Resolve from Maven Central (--version required) + +Options: + --version VER ai.rapids:cudf version + (required for --use-maven-central; otherwise if + omitted, exactly one version must exist under + ai/rapids/cudf/) + --cuda-version 12|13 Narrow classifiers to this CUDA major + -h, --help +EOF +} + +discover_version() { + local cudf_dir="${MAVEN_REPO}/ai/rapids/cudf" + if [[ ! -d "${cudf_dir}" ]]; then + die "No ai/rapids/cudf/ under ${MAVEN_REPO}" + fi + local -a versions=() + local d + for d in "${cudf_dir}"/*/; do + if [[ ! -d "${d}" ]]; then + continue + fi + versions+=("$(basename "${d}")") + done + if [[ "${#versions[@]}" -eq 0 ]]; then + die "No version directories under ${cudf_dir}" + fi + if [[ "${#versions[@]}" -gt 1 ]]; then + die "Multiple versions under ${cudf_dir}; pass --version. Found: ${versions[*]}" + fi + printf '%s\n' "${versions[0]}" +} + +classifiers_for_arch() { + local cuda="${1:-}" + case "$(uname -m)" in + x86_64) + case "${cuda}" in + "") echo "unclassified,cuda12,cuda13" ;; + 12) echo "unclassified,cuda12" ;; + 13) echo "cuda13" ;; + *) die "--cuda-version must be 12 or 13 (got: ${cuda})" ;; + esac + ;; + aarch64|arm64) + case "${cuda}" in + "") echo "cuda12-arm64,cuda13-arm64" ;; + 12) echo "cuda12-arm64" ;; + 13) echo "cuda13-arm64" ;; + *) die "--cuda-version must be 12 or 13 (got: ${cuda})" ;; + esac + ;; + *) die "Unsupported arch $(uname -m)" ;; + esac +} + +jar_for_classifier() { + local c="$1" + if [[ "${c}" == "unclassified" ]]; then + echo "${MAVEN_REPO}/ai/rapids/cudf/${VERSION}/cudf-${VERSION}.jar" + else + echo "${MAVEN_REPO}/ai/rapids/cudf/${VERSION}/cudf-${VERSION}-${c}.jar" + fi +} + +ensure_image() { + local major="$1" + local tag="cudf-java-smoke:cuda${major}" + local dockerfile="${SMOKE_TESTS_ROOT}/docker/Dockerfile.cuda${major}" + if ! docker image inspect "${tag}" >/dev/null 2>&1; then + info "Building ${tag}" + docker build -t "${tag}" -f "${dockerfile}" "${SMOKE_TESTS_ROOT}/docker" >&2 + fi + echo "${tag}" +} + +run_smoke() { + local classifier="$1" + local log_file="${CACHE_DIR}/logs/smoke-${classifier}.log" + mkdir -p "${CACHE_DIR}/logs" + + local -a mvn_cmd=(mvn -B "-Dcudf.version=${VERSION}") + if [[ "${classifier}" == "unclassified" ]]; then + mvn_cmd+=(-Dcudf.unclassified=true) + else + mvn_cmd+=("-Dcuda.classifier=${classifier}") + fi + mvn_cmd+=(package exec:java) + + local major=12 + case "${classifier}" in + *cuda13*) major=13 ;; + esac + local tag + tag="$(ensure_image "${major}")" + + # Maven writes compile output under target/; keep the tree writable. + mkdir -p "${CACHE_DIR}/m2-container" + + local -a docker_cmd=( + docker run --rm --gpus all + --user "$(id -u):$(id -g)" + -e HOME=/tmp + -e MAVEN_OPTS=-Duser.home=/tmp + -v "${SMOKE_TESTS_ROOT}:/smoke" + -v "${CACHE_DIR}/m2-container:/tmp/.m2" + -w /smoke + ) + + info "Smoke classifier=${classifier} version=${VERSION}" + set +e + if [[ "${USE_CENTRAL}" -eq 1 ]]; then + "${docker_cmd[@]}" \ + "${tag}" \ + "${mvn_cmd[@]}" \ + -Dcudf.smoke.central=true \ + -Dmaven.repo.local=/tmp/.m2/repository \ + >"${log_file}" 2>&1 + else + "${docker_cmd[@]}" \ + -v "${MAVEN_REPO}:/maven-repo:ro" \ + "${tag}" \ + "${mvn_cmd[@]}" \ + -Dcudf.maven.repo=/maven-repo \ + -Dmaven.repo.local=/tmp/.m2/repository \ + >"${log_file}" 2>&1 + fi + local rc=$? + set -e + cat "${log_file}" + + if [[ "${rc}" -ne 0 ]]; then + return 1 + fi + if ! grep -F -q "${PARQUET_WARN_NEEDLE}" "${log_file}"; then + warn "Missing expected CUDF_LOG_WARN in ${log_file}" + warn " needle: ${PARQUET_WARN_NEEDLE}" + return 1 + fi + return 0 +} + +main() { + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) print_help; exit 0 ;; + --artifact-url) + require_value "$1" "${2:-}" + set_mode "artifact-url" + ARTIFACT_URL="$2" + shift 2 + ;; + --maven-repo-dir) + require_value "$1" "${2:-}" + set_mode "maven-repo-dir" + MAVEN_REPO="$2" + shift 2 + ;; + --use-maven-home) + set_mode "use-maven-home" + MAVEN_REPO="${HOME}/.m2/repository" + shift + ;; + --use-maven-central) + set_mode "use-maven-central" + USE_CENTRAL=1 + shift + ;; + --version) + require_value "$1" "${2:-}" + VERSION="$2" + shift 2 + ;; + --cuda-version) + require_value "$1" "${2:-}" + CUDA_VERSION="$2" + shift 2 + ;; + *) die "Unknown argument: $1 (try --help)" ;; + esac + done + + if [[ -z "${MODE}" ]]; then + die "Exactly one source mode is required (try --help)" + fi + if ! command -v docker >/dev/null 2>&1; then + die "docker is required" + fi + + if [[ "${MODE}" == "artifact-url" ]]; then + MAVEN_REPO="$("${SCRIPT_DIR}/fetch_bundle.sh" --artifact-url "${ARTIFACT_URL}")" + fi + + if [[ "${USE_CENTRAL}" -eq 0 ]]; then + if [[ ! -d "${MAVEN_REPO}/ai/rapids/cudf" ]]; then + die "No ai/rapids/cudf/ under ${MAVEN_REPO}" + fi + MAVEN_REPO="$(cd "${MAVEN_REPO}" && pwd)" + if [[ -z "${VERSION}" ]]; then + VERSION="$(discover_version)" + elif [[ ! -d "${MAVEN_REPO}/ai/rapids/cudf/${VERSION}" ]]; then + die "Version ${VERSION} not under ${MAVEN_REPO}/ai/rapids/cudf/" + fi + else + if [[ -z "${VERSION}" ]]; then + die "--use-maven-central requires --version" + fi + fi + + local classifiers + classifiers="$(classifiers_for_arch "${CUDA_VERSION}")" + + info "Mode: ${MODE}" + if [[ "${USE_CENTRAL}" -eq 0 ]]; then + info "Maven repo: ${MAVEN_REPO}" + fi + info "Version: ${VERSION}" + info "Classifiers: ${classifiers}" + + # Force Maven to resolve cudf from the source currently under test. + rm -rf "${CACHE_DIR}/m2-container/repository/ai/rapids/cudf/${VERSION:?}" + + local failed=0 + local ran=0 + local c jar + local -a classifier_list + IFS=',' read -r -a classifier_list <<< "${classifiers}" + for c in "${classifier_list[@]}"; do + # Trim surrounding whitespace from comma-split tokens (e.g. " cuda12"). + c="$(echo "$c" | xargs)" + if [[ -z "${c}" ]]; then + continue + fi + if [[ "${USE_CENTRAL}" -eq 0 ]]; then + jar="$(jar_for_classifier "${c}")" + if [[ ! -f "${jar}" ]]; then + warn "Skipping missing classifier '${c}' (${jar})" + continue + fi + fi + ran=$((ran + 1)) + if run_smoke "${c}"; then + info "PASS: ${c}" + else + warn "FAIL: ${c}" + failed=1 + fi + done + + if [[ "${ran}" -eq 0 ]]; then + die "No classifier JARs were smoke tested (all missing or none selected)" + fi + if [[ "${failed}" -ne 0 ]]; then + die "One or more classifier smoke tests failed" + fi + info "All classifier smoke tests passed" +} + +main "$@" diff --git a/java/smoke-tests/docker/Dockerfile.cuda12 b/java/smoke-tests/docker/Dockerfile.cuda12 new file mode 100644 index 000000000000..47d0f752fbde --- /dev/null +++ b/java/smoke-tests/docker/Dockerfile.cuda12 @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. +# SPDX-License-Identifier: Apache-2.0 +FROM nvidia/cuda:12.9.1-runtime-ubuntu24.04 + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + openjdk-17-jdk-headless \ + maven \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && ln -sfn "$(dirname $(dirname $(readlink -f $(which javac))))" /usr/lib/jvm/cudf-smoke-jdk + +ENV JAVA_HOME=/usr/lib/jvm/cudf-smoke-jdk +ENV PATH="${JAVA_HOME}/bin:${PATH}" diff --git a/java/smoke-tests/docker/Dockerfile.cuda13 b/java/smoke-tests/docker/Dockerfile.cuda13 new file mode 100644 index 000000000000..4424ffa7930e --- /dev/null +++ b/java/smoke-tests/docker/Dockerfile.cuda13 @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. +# SPDX-License-Identifier: Apache-2.0 +FROM nvidia/cuda:13.0.1-runtime-ubuntu24.04 + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + openjdk-17-jdk-headless \ + maven \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* \ + && ln -sfn "$(dirname $(dirname $(readlink -f $(which javac))))" /usr/lib/jvm/cudf-smoke-jdk + +ENV JAVA_HOME=/usr/lib/jvm/cudf-smoke-jdk +ENV PATH="${JAVA_HOME}/bin:${PATH}" diff --git a/java/smoke-tests/pom.xml b/java/smoke-tests/pom.xml new file mode 100644 index 000000000000..3b3dd342af11 --- /dev/null +++ b/java/smoke-tests/pom.xml @@ -0,0 +1,113 @@ + + + + 4.0.0 + + ai.rapids + cudf-java-smoke-tests + 1.0.0-SNAPSHOT + jar + + cudf-java-smoke-tests + + Smoke tests for published cuDF Java classifier JARs. + Resolves ai.rapids:cudf from a local Maven-repo tree (file://) or + Maven Central and runs SanityCudf with only cudf + slf4j on the classpath. + + + + UTF-8 + 17 + 26.10.0-SNAPSHOT + ${user.home}/.unused-do-not-use + cuda12 + 1.7.30 + ai.rapids.cudf.smoke.SanityCudf + + + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + + + + local-maven-repo + + + !cudf.smoke.central + + + + + cudf-under-test + file://${cudf.maven.repo} + + + + + + classified + + + !cudf.unclassified + + + + + ai.rapids + cudf + ${cudf.version} + ${cuda.classifier} + + + + + + unclassified + + + cudf.unclassified + true + + + + + ai.rapids + cudf + ${cudf.version} + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${maven.compiler.release} + + + + org.codehaus.mojo + exec-maven-plugin + 3.5.0 + + ${main.class} + + + + + diff --git a/java/smoke-tests/src/main/java/ai/rapids/cudf/smoke/SanityCudf.java b/java/smoke-tests/src/main/java/ai/rapids/cudf/smoke/SanityCudf.java new file mode 100644 index 000000000000..a46ddc420123 --- /dev/null +++ b/java/smoke-tests/src/main/java/ai/rapids/cudf/smoke/SanityCudf.java @@ -0,0 +1,232 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package ai.rapids.cudf.smoke; + +import ai.rapids.cudf.BinaryOp; +import ai.rapids.cudf.ColumnVector; +import ai.rapids.cudf.Cuda; +import ai.rapids.cudf.DType; +import ai.rapids.cudf.DefaultHostMemoryAllocator; +import ai.rapids.cudf.DeviceMemoryBuffer; +import ai.rapids.cudf.HostBufferConsumer; +import ai.rapids.cudf.HostColumnVector; +import ai.rapids.cudf.HostMemoryBuffer; +import ai.rapids.cudf.MultiBufferDataSource; +import ai.rapids.cudf.ParquetChunkedReader; +import ai.rapids.cudf.ParquetOptions; +import ai.rapids.cudf.ParquetWriterOptions; +import ai.rapids.cudf.Scalar; +import ai.rapids.cudf.Table; +import ai.rapids.cudf.TableWriter; +import ai.rapids.cudf.nvcomp.BatchedLZ4Compressor; +import ai.rapids.cudf.nvcomp.BatchedLZ4Decompressor; + +/** + * Core cudf-java smoke test exercised once per published classifier JAR. + * Includes a small nvcomp LZ4 round-trip so static-libcudf JARs exercise + * nvcomp symbols linked into libcudf (not a separate libnvcomp.so), and a + * chunked Parquet DataSource read that triggers CUDF_LOG_WARN (native + * rapids_logger / spdlog path) when pass_read_limit is derived. + */ +public final class SanityCudf { + private SanityCudf() {} + + private static void step(int n, String label) { + System.out.printf("[%d/9] %s ...%n", n, label); + } + + private static void ok(String label) { + System.out.println("OK: " + label); + } + + private static void check(boolean cond, String msg) { + if (!cond) { + throw new IllegalStateException("ASSERT: " + msg); + } + } + + /** Collect parquet bytes written via HostBufferConsumer. */ + private static final class CollectingConsumer implements HostBufferConsumer, AutoCloseable { + private final HostMemoryBuffer buffer = HostMemoryBuffer.allocate(1024 * 1024); + private long offset = 0; + + @Override + public void handleBuffer(HostMemoryBuffer src, long len) { + try { + buffer.copyFromHostBuffer(offset, src, 0, len); + offset += len; + } finally { + src.close(); + } + } + + long length() { + return offset; + } + + HostMemoryBuffer buffer() { + return buffer; + } + + @Override + public void close() { + buffer.close(); + } + } + + /** + * Write a tiny parquet table, then open it with the DataSource-only + * ParquetChunkedReader ctor (chunk limit set, no pass limit). That native + * path calls derive_pass_read_limit() and emits CUDF_LOG_WARN - exercising + * the linked rapids_logger/spdlog stack without needing external libspdlog. + */ + private static void parquetChunkedLoggerSmoke() { + ParquetWriterOptions writeOpts = + ParquetWriterOptions.builder().withColumns(false, "a").build(); + try (CollectingConsumer consumer = new CollectingConsumer()) { + try (ColumnVector col = ColumnVector.fromInts(1, 2, 3, 4, 5); + Table table = new Table(col); + TableWriter writer = Table.writeParquetChunked(writeOpts, consumer)) { + writer.write(table); + } + check(consumer.length() > 0, "expected non-empty parquet bytes"); + try (HostMemoryBuffer slice = consumer.buffer().slice(0, consumer.length()); + MultiBufferDataSource ds = new MultiBufferDataSource(slice); + ParquetChunkedReader reader = + new ParquetChunkedReader(64 * 1024L, ParquetOptions.DEFAULT, ds)) { + long rows = 0; + while (reader.hasNext()) { + try (Table chunk = reader.readChunk()) { + if (chunk != null) { + rows += chunk.getRowCount(); + } + } + } + check(rows == 5, "expected 5 rows from chunked parquet logger smoke"); + } + } + } + + /** Minimal LZ4 compress/decompress round-trip via ai.rapids.cudf.nvcomp. */ + private static void nvcompLz4RoundTrip() { + final long chunkSize = 64 * 1024; + final Cuda.Stream stream = Cuda.DEFAULT_STREAM; + final long[] data = new long[4096]; + for (int i = 0; i < data.length; i++) { + data[i] = i; + } + + DeviceMemoryBuffer original = null; + DeviceMemoryBuffer[] compressed = null; + DeviceMemoryBuffer decompressed = null; + try (HostMemoryBuffer hostIn = + DefaultHostMemoryAllocator.get().allocate(data.length * 8L)) { + hostIn.setLongs(0, data, 0, data.length); + original = DeviceMemoryBuffer.allocate(hostIn.getLength()); + original.copyFromHostBuffer(hostIn); + // compress() takes ownership / closes inputs; keep a live ref for compare. + original.incRefCount(); + + BatchedLZ4Compressor comp = + new BatchedLZ4Compressor(chunkSize, Long.MAX_VALUE); + compressed = comp.compress(new DeviceMemoryBuffer[]{original}, stream); + check(compressed != null && compressed.length == 1, "expected 1 compressed buffer"); + check(compressed[0] != null && compressed[0].getLength() > 0, + "compressed buffer should be non-empty"); + + decompressed = DeviceMemoryBuffer.allocate(hostIn.getLength()); + BatchedLZ4Decompressor decomp = new BatchedLZ4Decompressor(chunkSize); + // decompressAsync takes ownership of compressed buffers. + decomp.decompressAsync(compressed, new DeviceMemoryBuffer[]{decompressed}, stream); + compressed = null; // owned/closed by decompressAsync + stream.sync(); + + try (HostMemoryBuffer hostOut = + DefaultHostMemoryAllocator.get().allocate(decompressed.getLength())) { + hostOut.copyFromDeviceBuffer(decompressed); + check(hostOut.getLength() == hostIn.getLength(), "decompressed size mismatch"); + for (int i = 0; i < data.length; i++) { + check(hostOut.getLong(i * 8L) == data[i], "nvcomp mismatch at long[" + i + "]"); + } + } + } finally { + if (original != null) { + original.close(); + } + if (compressed != null) { + for (DeviceMemoryBuffer b : compressed) { + if (b != null) { + b.close(); + } + } + } + if (decompressed != null) { + decompressed.close(); + } + } + } + + public static void main(String[] args) { + step(1, "Native deps load"); + try (ColumnVector ints = ColumnVector.fromInts(1, 2, 3, 4, 5)) { + check(ints.getRowCount() == 5, "expected 5 rows after fromInts"); + ok("Native deps load"); + + step(2, "ColumnVector + Table"); + try (ColumnVector more = ColumnVector.fromInts(10, 20, 30, 40, 50); + Table table = new Table(ints, more)) { + check(table.getNumberOfColumns() == 2, "expected 2 columns"); + check(table.getRowCount() == 5, "expected 5 table rows"); + ok("ColumnVector + Table"); + } + + step(3, "Filter"); + try (Scalar three = Scalar.fromInt(3); + ColumnVector mask = ints.binaryOp(BinaryOp.GREATER, three, DType.BOOL8); + Table table = new Table(ints); + Table filtered = table.filter(mask)) { + check(filtered.getRowCount() == 2, "expected 2 rows after filter (>3)"); + ok("Filter"); + } + + step(4, "Aggregation"); + try (Scalar sum = ints.sum(DType.INT64)) { + check(sum.isValid(), "sum scalar should be valid"); + check(sum.getLong() == 15L, "sum should be 15"); + ok("Aggregation (sum)"); + } + + step(5, "String column create + length"); + try (ColumnVector strs = ColumnVector.fromStrings("a", "bb", "ccc"); + ColumnVector lengths = strs.getCharLengths(); + HostColumnVector hostLens = lengths.copyToHost()) { + check(strs.getRowCount() == 3, "expected 3 string rows"); + check(hostLens.getInt(0) == 1, "len[0]==1"); + check(hostLens.getInt(1) == 2, "len[1]==2"); + check(hostLens.getInt(2) == 3, "len[2]==3"); + ok("String column create + length"); + } + + step(6, "Host round-trip"); + try (HostColumnVector host = ints.copyToHost()) { + check(host.getInt(0) == 1, "host[0]==1"); + check(host.getInt(4) == 5, "host[4]==5"); + ok("Host round-trip"); + } + + step(7, "nvcomp LZ4 round-trip"); + nvcompLz4RoundTrip(); + ok("nvcomp LZ4 round-trip"); + + step(8, "Parquet chunked logger smoke"); + parquetChunkedLoggerSmoke(); + ok("Parquet chunked logger smoke (CUDF_LOG_WARN path)"); + + step(9, "Resource close"); + ok("Clean close via try-with-resources"); + } + System.out.println("ALL STEPS PASSED"); + } +} From a0e670b362a6eebdea8101f0194d1d59659b24b6 Mon Sep 17 00:00:00 2001 From: Paul Aiyedun <53453937+paul-aiyedun@users.noreply.github.com> Date: Sat, 8 Aug 2026 00:05:08 +0000 Subject: [PATCH 2/2] Fix handling of central-bundle.zip --- .github/workflows/pr.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 462f084b47f4..b61b3ef0be24 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -49,11 +49,18 @@ jobs: merge-multiple: true - name: Locate Maven-repo root run: | + # The maven-central-bundle artifact wraps a nested central-bundle.zip + # that holds the ai/rapids/cudf/ Maven layout. Unpack it if present. + bundle="$(find "${CUDF_SMOKE_MAVEN_REPO}" -type f -name 'central-bundle.zip' | head -n 1 || true)" + if [[ -n "${bundle}" ]]; then + echo "Unpacking central bundle: ${bundle}" + unzip -q -o "${bundle}" -d "${CUDF_SMOKE_MAVEN_REPO}/bundle-extracted" + fi if [[ -d "${CUDF_SMOKE_MAVEN_REPO}/ai/rapids/cudf" ]]; then echo "CUDF_SMOKE_MAVEN_REPO_DIR=${CUDF_SMOKE_MAVEN_REPO}" >> "${GITHUB_ENV}" exit 0 fi - # download-artifact may nest under the artifact name directory. + # download-artifact / bundle extraction may nest ai/rapids/cudf deeper. found="$(find "${CUDF_SMOKE_MAVEN_REPO}" -type d -path '*/ai/rapids/cudf' | head -n 1 || true)" if [[ -z "${found}" ]]; then echo "ERROR: no ai/rapids/cudf/ under ${CUDF_SMOKE_MAVEN_REPO}" >&2