diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index ac9c95f49..f63107d8f 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -29,8 +29,31 @@ jobs: flag-name: run-jvm-${{ join(matrix.*, '-') }} parallel: true base-path: src/main/java + + graalvm-native-image: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup GraalVM + uses: graalvm/setup-graalvm@v1 + with: + distribution: graalvm + java-version: "21" + components: native-image + cache: maven + - name: Compile smoke test + run: ./mvnw -B -DskipTests test-compile dependency:build-classpath -Dmdep.outputFile=target/test-classpath.txt + - name: Build native image + run: | + native-image --no-fallback --enable-url-protocols=http \ + -cp "target/classes:target/test-classes:$(cat target/test-classpath.txt)" \ + io.getunleash.repository.GraalVmHttpFeatureFetcherSmoke \ + target/graalvm-http-feature-fetcher-smoke + - name: Run native image smoke test + run: ./target/graalvm-http-feature-fetcher-smoke finish: - needs: build + needs: [build, graalvm-native-image] if: ${{ always() }} runs-on: ubuntu-latest steps: diff --git a/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java b/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java index 0e389f2c7..d74d1f5b8 100644 --- a/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java +++ b/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java @@ -75,7 +75,8 @@ private ClientFeaturesResponse getFeatureResponse( try (BufferedReader reader = new BufferedReader( new InputStreamReader( - request.getInputStream(), StandardCharsets.UTF_8))) { + (InputStream) request.getContent(), + StandardCharsets.UTF_8))) { String clientFeatures = reader.lines().collect(Collectors.joining("\n")); return ClientFeaturesResponse.updated(clientFeatures); diff --git a/src/test/java/io/getunleash/repository/GraalVmHttpFeatureFetcherSmoke.java b/src/test/java/io/getunleash/repository/GraalVmHttpFeatureFetcherSmoke.java new file mode 100644 index 000000000..fb290e461 --- /dev/null +++ b/src/test/java/io/getunleash/repository/GraalVmHttpFeatureFetcherSmoke.java @@ -0,0 +1,78 @@ +package io.getunleash.repository; + +import io.getunleash.event.ClientFeaturesResponse; +import io.getunleash.util.UnleashConfig; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.FutureTask; + +public class GraalVmHttpFeatureFetcherSmoke { + private static final String FEATURE_NAME = "graalvm-smoke-test"; + private static final String RESPONSE_BODY = + "{\"version\":1,\"features\":[{\"name\":\"" + + FEATURE_NAME + + "\",\"enabled\":true,\"strategies\":[{\"name\":\"default\"}]}]}"; + + public static void main(String[] args) throws Exception { + try (ServerSocket serverSocket = new ServerSocket(0)) { + FutureTask server = + new FutureTask<>( + () -> { + serveOneRequest(serverSocket); + return null; + }); + new Thread(server, "graalvm-smoke-http").start(); + + UnleashConfig config = + UnleashConfig.builder() + .appName("graalvm-native-image-smoke-test") + .unleashAPI( + new URI( + "http://127.0.0.1:" + + serverSocket.getLocalPort() + + "/api/")) + .build(); + + ClientFeaturesResponse response = new HttpFeatureFetcher(config).fetchFeatures(); + boolean found = + response.getFeatures().stream() + .anyMatch(feature -> FEATURE_NAME.equals(feature.getName())); + if (response.getStatus() != ClientFeaturesResponse.Status.CHANGED || !found) { + throw new IllegalStateException("Native image smoke test did not fetch features"); + } + + server.get(); + } + } + + private static void serveOneRequest(ServerSocket serverSocket) throws Exception { + try (Socket socket = serverSocket.accept(); + BufferedReader reader = + new BufferedReader( + new InputStreamReader( + socket.getInputStream(), StandardCharsets.US_ASCII)); + OutputStream output = socket.getOutputStream()) { + String line; + while ((line = reader.readLine()) != null && !line.isEmpty()) { + // Drain request headers before writing the response. + } + + byte[] body = RESPONSE_BODY.getBytes(StandardCharsets.UTF_8); + output.write( + ("HTTP/1.1 200 OK\r\n" + + "Content-Type: application/json\r\n" + + "Content-Length: " + + body.length + + "\r\n" + + "Connection: close\r\n\r\n") + .getBytes(StandardCharsets.US_ASCII)); + output.write(body); + output.flush(); + } + } +}