name: Java 9+ Module Support on: push: branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] # Cancel superseded in-progress runs for the same PR. Runs # triggered by push events are never cancelled. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: # Test Java 9+ module support (JPMS) # Verifies that module-info.java is properly compiled and the resulting # JAR can be used with jlink to create custom Java runtimes. # See GitHub issue #85 for background. module-test: strategy: matrix: os: [ 'ubuntu-latest' ] jdk_version: [ '11', '17', '21' ] runs-on: ${{ matrix.os }} name: Module Test (JDK ${{ matrix.jdk_version }}) steps: - uses: actions/checkout@v4 - name: Setup JUnit uses: ./.github/actions/setup-junit # Cache the installed wolfSSL build. The key matches the one built # in linux-common.yml for the same configure flags, so this job # shares the cache with the main CI matrix. - name: Resolve wolfSSL cache key id: wolfssl-key env: WOLFSSL_CONFIGURE: '--enable-jni' run: | SHA=$(git ls-remote https://github.com/wolfSSL/wolfssl.git \ refs/heads/master | cut -f1) if [ -z "$SHA" ]; then echo "Failed to resolve wolfSSL master SHA" >&2 exit 1 fi CFG_HASH=$(printf '%s' "$WOLFSSL_CONFIGURE" | \ shasum -a 256 | cut -c1-16) KEY="wolfssl-${{ runner.os }}-${{ runner.arch }}-$SHA-$CFG_HASH" echo "key=$KEY" >> "$GITHUB_OUTPUT" - name: Restore cached wolfSSL install id: cache-wolfssl uses: actions/cache/restore@v4 with: path: build-dir key: ${{ steps.wolfssl-key.outputs.key }} - name: Build native wolfSSL if: steps.cache-wolfssl.outputs.cache-hit != 'true' uses: wolfSSL/actions-build-autotools-project@v1 with: repository: wolfSSL/wolfssl ref: master path: wolfssl configure: --enable-jni check: false install: true # Save right after building (not at job end) so a later test # failure does not prevent the cache from being populated. - name: Save wolfSSL install to cache if: steps.cache-wolfssl.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: build-dir key: ${{ steps.wolfssl-key.outputs.key }} - name: Setup Java uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: ${{ matrix.jdk_version }} - name: Set LD_LIBRARY_PATH run: | echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV" - name: Build JNI library run: ./java.sh $GITHUB_WORKSPACE/build-dir - name: Build JAR with module support (ant) run: ant - name: Verify module-info.class exists in JAR run: | echo "Checking for module-info.class in wolfssl-jsse.jar..." if jar tf lib/wolfssl-jsse.jar | grep -q "module-info.class"; then echo "SUCCESS: module-info.class found in JAR" else echo "FAILURE: module-info.class not found in JAR" echo "JAR contents:" jar tf lib/wolfssl-jsse.jar | head -20 exit 1 fi - name: Verify module descriptor with jar --describe-module run: | echo "Describing module in wolfssl-jsse.jar..." jar --describe-module --file=lib/wolfssl-jsse.jar echo "" echo "Verifying module name is 'com.wolfssl'..." MODULE_NAME=$(jar --describe-module --file=lib/wolfssl-jsse.jar 2>&1 | head -1 | cut -d' ' -f1) if [ "$MODULE_NAME" = "com.wolfssl" ]; then echo "SUCCESS: Module name is correct: $MODULE_NAME" else echo "FAILURE: Expected module name 'com.wolfssl', got '$MODULE_NAME'" exit 1 fi - name: Verify module exports correct packages run: | echo "Verifying module exports..." EXPORTS=$(jar --describe-module --file=lib/wolfssl-jsse.jar 2>&1) echo "$EXPORTS" echo "" if echo "$EXPORTS" | grep -q "exports com.wolfssl"; then echo "SUCCESS: exports com.wolfssl" else echo "FAILURE: missing 'exports com.wolfssl'" exit 1 fi if echo "$EXPORTS" | grep -q "exports com.wolfssl.provider.jsse"; then echo "SUCCESS: exports com.wolfssl.provider.jsse" else echo "FAILURE: missing 'exports com.wolfssl.provider.jsse'" exit 1 fi - name: Test jlink can create runtime with module run: | echo "Testing jlink integration..." jlink \ --module-path lib/wolfssl-jsse.jar \ --add-modules com.wolfssl \ --output test-jlink-runtime \ --no-header-files \ --no-man-pages echo "" echo "SUCCESS: jlink created custom runtime" echo "Runtime modules:" ./test-jlink-runtime/bin/java --list-modules echo "" echo "Verifying com.wolfssl module is present..." if ./test-jlink-runtime/bin/java --list-modules | grep -q "com.wolfssl"; then echo "SUCCESS: com.wolfssl module found in custom runtime" else echo "FAILURE: com.wolfssl module not found in custom runtime" exit 1 fi - name: Clean up jlink test runtime run: rm -rf test-jlink-runtime - name: Run standard tests to verify module doesn't break functionality run: ant test - name: Clean ant build for Maven test run: ant clean - name: Maven build and verify module-info in JAR run: | echo "Building with Maven..." mvn package -DskipTests -q echo "" MAVEN_JAR=$(ls target/wolfssl-jsse-*.jar) echo "Maven JAR: $MAVEN_JAR" echo "" echo "Checking for module-info.class in Maven-built JAR..." if jar tf "$MAVEN_JAR" | grep -q "module-info.class"; then echo "SUCCESS: module-info.class found in Maven JAR" else echo "FAILURE: module-info.class not found in Maven JAR" jar tf "$MAVEN_JAR" | head -20 exit 1 fi echo "" echo "Verifying Maven JAR module descriptor..." jar --describe-module --file="$MAVEN_JAR" - name: Clean Maven build run: mvn clean -q - name: Show logs on failure if: failure() || cancelled() run: | cat build/reports/*.txt 2>/dev/null || echo "No test reports found" # Verify Java 8 builds do NOT include module-info.class # This ensures the conditional compilation works correctly for Java 8 users java8-no-module-test: runs-on: ubuntu-latest name: Java 8 No Module Test steps: - uses: actions/checkout@v4 - name: Setup JUnit uses: ./.github/actions/setup-junit # Cache the installed wolfSSL build. The key matches the one built # in linux-common.yml for the same configure flags, so this job # shares the cache with the main CI matrix. - name: Resolve wolfSSL cache key id: wolfssl-key env: WOLFSSL_CONFIGURE: '--enable-jni' run: | SHA=$(git ls-remote https://github.com/wolfSSL/wolfssl.git \ refs/heads/master | cut -f1) if [ -z "$SHA" ]; then echo "Failed to resolve wolfSSL master SHA" >&2 exit 1 fi CFG_HASH=$(printf '%s' "$WOLFSSL_CONFIGURE" | \ shasum -a 256 | cut -c1-16) KEY="wolfssl-${{ runner.os }}-${{ runner.arch }}-$SHA-$CFG_HASH" echo "key=$KEY" >> "$GITHUB_OUTPUT" - name: Restore cached wolfSSL install id: cache-wolfssl uses: actions/cache/restore@v4 with: path: build-dir key: ${{ steps.wolfssl-key.outputs.key }} - name: Build native wolfSSL if: steps.cache-wolfssl.outputs.cache-hit != 'true' uses: wolfSSL/actions-build-autotools-project@v1 with: repository: wolfSSL/wolfssl ref: master path: wolfssl configure: --enable-jni check: false install: true # Save right after building (not at job end) so a later test # failure does not prevent the cache from being populated. - name: Save wolfSSL install to cache if: steps.cache-wolfssl.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: build-dir key: ${{ steps.wolfssl-key.outputs.key }} - name: Setup Java 8 uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: '8' - name: Set LD_LIBRARY_PATH run: | echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV" - name: Build JNI library run: ./java.sh $GITHUB_WORKSPACE/build-dir - name: Build JAR without module support (ant on Java 8) run: ant - name: Verify module-info.class is NOT in JAR (Java 8 build) run: | echo "Checking that module-info.class is NOT in wolfssl-jsse.jar (Java 8 build)..." if jar tf lib/wolfssl-jsse.jar | grep -q "module-info.class"; then echo "FAILURE: module-info.class should NOT be in JAR when built with Java 8" exit 1 else echo "SUCCESS: module-info.class correctly excluded from Java 8 build" fi - name: Run tests to verify Java 8 build works correctly run: ant test - name: Maven build and verify NO module-info in JAR (Java 8) run: | echo "Building with Maven on Java 8..." mvn package -DskipTests -q echo "" MAVEN_JAR=$(ls target/wolfssl-jsse-*.jar) echo "Maven JAR: $MAVEN_JAR" echo "" echo "Checking that module-info.class is NOT in Maven-built JAR..." if jar tf "$MAVEN_JAR" | grep -q "module-info.class"; then echo "FAILURE: module-info.class should NOT be in Maven JAR on Java 8" exit 1 else echo "SUCCESS: module-info.class correctly excluded from Maven Java 8 build" fi mvn clean -q - name: Show logs on failure if: failure() || cancelled() run: | cat build/reports/*.txt 2>/dev/null || echo "No test reports found"