name: Java Implementation Testing (FFM vs JNI) # Test both FFM and JNI implementations across multiple Java versions on: pull_request: branches: [ develop, main ] paths: - 'java/**' - 'CMakeBuildOptions.cmake' - 'CMakePresets.json' - 'config/cmake-presets/hidden-presets.json' - '.github/workflows/java-implementation-test.yml' - '.github/scripts/test-java-implementations.sh' workflow_call: inputs: java_versions: description: 'Java versions to test (comma-separated)' type: string required: false default: '11,17,21,24' test_mode: description: 'Test mode (build, maven, full)' type: string required: false default: 'build' platforms: description: 'Platforms to test' type: string required: false default: 'ubuntu-latest' workflow_dispatch: inputs: java_versions: description: 'Java versions to test' type: string required: false default: '11,17,21,24' test_mode: description: 'Test mode' type: choice required: false default: 'build' options: - 'build' - 'maven' - 'full' platforms: description: 'Platforms to test' type: choice required: false default: 'ubuntu-latest' options: - 'ubuntu-latest' - 'windows-latest' - 'macos-latest' - 'all-platforms' permissions: contents: read env: CMAKE_GENERATOR: Ninja jobs: setup-matrix: runs-on: ubuntu-latest outputs: matrix: ${{ steps.generate-matrix.outputs.matrix }} steps: - name: Generate test matrix id: generate-matrix env: JAVA_VERSIONS: ${{ inputs.java_versions || '11,17,21,25' }} PLATFORMS: ${{ inputs.platforms || 'ubuntu-latest' }} run: | # Expand platforms if needed if [[ "$PLATFORMS" == "all-platforms" ]]; then PLATFORMS="ubuntu-latest,windows-latest,macos-latest" fi # Generate matrix matrix_json="[" first_entry=true for platform in $(echo "$PLATFORMS" | tr ',' ' '); do for java_version in $(echo "$JAVA_VERSIONS" | tr ',' ' '); do # Determine available implementations if [[ $java_version -ge 25 ]]; then implementations="ffm jni" else implementations="jni" fi for impl in $implementations; do if [ "$first_entry" = true ]; then first_entry=false else matrix_json="$matrix_json," fi matrix_json="$matrix_json{\"os\":\"$platform\",\"java-version\":\"$java_version\",\"implementation\":\"$impl\"}" done done done matrix_json="$matrix_json]" echo "Generated matrix:" echo "$matrix_json" | jq '.' echo "matrix=$matrix_json" >> $GITHUB_OUTPUT test-implementations: needs: setup-matrix runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: ${{ fromJson(needs.setup-matrix.outputs.matrix) }} name: Test Java ${{ matrix.java-version }} ${{ matrix.implementation }} on ${{ matrix.os }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: recursive persist-credentials: false - name: Set up Java ${{ matrix.java-version }} (${{ matrix.implementation }}) uses: actions/setup-java@dd06d9cba3e5552c54d9f8ea23572deb30010f7c # v5 with: distribution: ${{ matrix.implementation == 'ffm' && 'oracle' || 'temurin' }} java-version: ${{ matrix.implementation == 'ffm' && '25' || matrix.java-version }} - name: Setup jextract (FFM builds only) if: ${{ matrix.implementation == 'ffm' }} uses: ./.github/actions/setup-jextract with: java-version: '25' - name: Setup Build Environment (Linux) if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y ninja-build libaec-dev zlib1g-dev - name: Setup Build Environment (macOS) if: runner.os == 'macOS' run: | brew install libaec - name: Setup Build Environment (Windows) if: runner.os == 'Windows' run: | choco install ninja - name: Cache CMake build uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 with: path: | build-test-* key: ${{ runner.os }}-java${{ matrix.java-version }}-${{ matrix.implementation }}-${{ hashFiles('**/CMakeLists.txt', 'CMakePresets.json') }} restore-keys: | ${{ runner.os }}-java${{ matrix.java-version }}-${{ matrix.implementation }}- ${{ runner.os }}-java${{ matrix.java-version }}- - name: Verify Java version and implementation compatibility run: | java -version echo "Testing Java ${{ matrix.java-version }} with ${{ matrix.implementation }} implementation" # Additional validation for FFM if [[ "${{ matrix.implementation }}" == "ffm" ]]; then if [[ ${{ matrix.java-version }} -lt 25 ]]; then echo "::error::FFM implementation requires Java 25, got Java ${{ matrix.java-version }}" exit 1 fi echo "FFM implementation validated for Java ${{ matrix.java-version }}" fi - name: Run implementation tests shell: bash env: TEST_MODE: ${{ inputs.test_mode || 'build' }} run: | chmod +x .github/scripts/test-java-implementations.sh .github/scripts/test-java-implementations.sh \ ${{ matrix.java-version }} \ ${{ matrix.implementation }} \ "$TEST_MODE" - name: Upload build artifacts on failure if: failure() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v5 with: name: build-logs-${{ matrix.os }}-java${{ matrix.java-version }}-${{ matrix.implementation }} path: | build-test-*/CMakeCache.txt build-test-*/CMakeFiles/CMakeError.log build-test-*/CMakeFiles/CMakeOutput.log retention-days: 7 - name: Upload Maven artifacts (if generated) if: inputs.test_mode == 'maven' || inputs.test_mode == 'full' uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v5 with: name: maven-artifacts-${{ matrix.os }}-java${{ matrix.java-version }}-${{ matrix.implementation }} path: | build-test-*/java/**/target/*.jar build-test-*/java/**/pom.xml retention-days: 3 validate-artifacts: needs: [setup-matrix, test-implementations] runs-on: ubuntu-latest if: inputs.test_mode == 'maven' || inputs.test_mode == 'full' steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: Download all Maven artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: maven-artifacts-* path: artifacts/ - name: Validate artifact differentiation run: | echo "Validating Maven artifact differentiation..." # Check for FFM artifacts ffm_artifacts=$(find artifacts/ -name "*hdf5-java-ffm*" | wc -l) jni_artifacts=$(find artifacts/ -name "*hdf5-java-jni*" | wc -l) echo "Found $ffm_artifacts FFM artifacts and $jni_artifacts JNI artifacts" if [[ $ffm_artifacts -eq 0 && $jni_artifacts -eq 0 ]]; then echo "::error::No Maven artifacts found!" exit 1 fi # Verify no mixed artifacts mixed_artifacts=$(find artifacts/ -name "*hdf5-java-*" | grep -v -E "(ffm|jni)" | wc -l) if [[ $mixed_artifacts -gt 0 ]]; then echo "::error::Found artifacts without proper FFM/JNI differentiation" find artifacts/ -name "*hdf5-java-*" | grep -v -E "(ffm|jni)" exit 1 fi echo "✅ Artifact differentiation validation passed" - name: Validate POM files run: | echo "Validating POM file contents..." for pom in $(find artifacts/ -name "pom.xml"); do echo "Checking POM: $pom" # Extract artifact ID artifact_id=$(grep -o 'hdf5-java-[^<]*' "$pom" | sed 's/<[^>]*>//g') echo "Artifact ID: $artifact_id" # Validate implementation metadata if grep -q "hdf5-java-ffm" "$pom"; then if ! grep -q "FFM" "$pom"; then echo "::error::FFM POM missing implementation metadata" exit 1 fi echo "✅ FFM POM validation passed" elif grep -q "hdf5-java-jni" "$pom"; then if ! grep -q "JNI" "$pom"; then echo "::error::JNI POM missing implementation metadata" exit 1 fi echo "✅ JNI POM validation passed" else echo "::error::POM has unrecognized artifact ID: $artifact_id" exit 1 fi done report-results: needs: [setup-matrix, test-implementations, validate-artifacts] runs-on: ubuntu-latest if: always() steps: - name: Generate test report env: JAVA_VERSIONS: ${{ inputs.java_versions || '11,17,21,25' }} TEST_MODE: ${{ inputs.test_mode || 'build' }} PLATFORMS: ${{ inputs.platforms || 'ubuntu-latest' }} run: | echo "## Java Implementation Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Test Configuration" >> $GITHUB_STEP_SUMMARY echo "- **Java Versions**: $JAVA_VERSIONS" >> $GITHUB_STEP_SUMMARY echo "- **Test Mode**: $TEST_MODE" >> $GITHUB_STEP_SUMMARY echo "- **Platforms**: $PLATFORMS" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Report job statuses if [[ "${{ needs.test-implementations.result }}" == "success" ]]; then echo "✅ **Implementation Tests**: PASSED" >> $GITHUB_STEP_SUMMARY else echo "❌ **Implementation Tests**: FAILED" >> $GITHUB_STEP_SUMMARY fi if [[ "${{ needs.validate-artifacts.result }}" == "success" ]]; then echo "✅ **Artifact Validation**: PASSED" >> $GITHUB_STEP_SUMMARY elif [[ "${{ needs.validate-artifacts.result }}" == "skipped" ]]; then echo "⏭️ **Artifact Validation**: SKIPPED" >> $GITHUB_STEP_SUMMARY else echo "❌ **Artifact Validation**: FAILED" >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY echo "### Implementation Matrix" >> $GITHUB_STEP_SUMMARY echo "| Java Version | FFM Support | JNI Support |" >> $GITHUB_STEP_SUMMARY echo "|--------------|-------------|-------------|" >> $GITHUB_STEP_SUMMARY echo "| 11 | ❌ | ✅ |" >> $GITHUB_STEP_SUMMARY echo "| 17 | ❌ | ✅ |" >> $GITHUB_STEP_SUMMARY echo "| 21 | ❌ | ✅ |" >> $GITHUB_STEP_SUMMARY echo "| 24+ | ✅ (optional) | ✅ (default) |" >> $GITHUB_STEP_SUMMARY