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' 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 run: | # Parse inputs JAVA_VERSIONS="${{ inputs.java_versions || '11,17,21,25' }}" PLATFORMS="${{ inputs.platforms || 'ubuntu-latest' }}" # 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@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: submodules: recursive - name: Set up Java ${{ matrix.java-version }} (${{ matrix.implementation }}) uses: actions/setup-java@f2beeb24e141e01a676f977032f5a29d81c9e27e # 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 ninja libaec - name: Setup Build Environment (Windows) if: runner.os == 'Windows' run: | choco install ninja - name: Cache CMake build uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 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 run: | chmod +x .github/scripts/test-java-implementations.sh .github/scripts/test-java-implementations.sh \ ${{ matrix.java-version }} \ ${{ matrix.implementation }} \ ${{ inputs.test_mode || 'build' }} - name: Upload build artifacts on failure if: failure() uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # 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@330a01c490aca151604b8cf639adc76d48f6c5d4 # 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@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Download all Maven artifacts uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 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 run: | echo "## Java Implementation Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "### Test Configuration" >> $GITHUB_STEP_SUMMARY echo "- **Java Versions**: ${{ inputs.java_versions || '11,17,21,25' }}" >> $GITHUB_STEP_SUMMARY echo "- **Test Mode**: ${{ inputs.test_mode || 'build' }}" >> $GITHUB_STEP_SUMMARY echo "- **Platforms**: ${{ inputs.platforms || 'ubuntu-latest' }}" >> $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