diff --git a/pom.xml b/pom.xml index ef2976d94..6399b55d5 100644 --- a/pom.xml +++ b/pom.xml @@ -115,20 +115,20 @@ org.assertj assertj-core - 3.26.3 + 3.27.6 test org.mockito mockito-core - 4.8.1 + 5.20.0 test com.github.tomakehurst wiremock-jre8 - 2.35.2 + 3.0.1 test @@ -177,6 +177,13 @@ org.apache.maven.plugins maven-dependency-plugin 3.8.1 + + + + properties + + + org.apache.maven.plugins @@ -219,7 +226,7 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.13 prepare-agent @@ -410,6 +417,9 @@ org.apache.maven.plugins maven-surefire-plugin 3.5.2 + + @{argLine} -javaagent:${org.mockito:mockito-core:jar} + diff --git a/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java b/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java index 53f2ab22b..a8863bb10 100644 --- a/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java +++ b/src/main/java/io/getunleash/repository/HttpFeatureFetcher.java @@ -5,15 +5,13 @@ import io.getunleash.UnleashException; import io.getunleash.event.ClientFeaturesResponse; import io.getunleash.util.UnleashConfig; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.stream.Collectors; +import java.util.zip.GZIPInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,15 +57,30 @@ private ClientFeaturesResponse getFeatureResponse( if (responseCode < 300) { etag = Optional.ofNullable(request.getHeaderField("ETag")); - - try (BufferedReader reader = - new BufferedReader( - new InputStreamReader( - (InputStream) request.getContent(), StandardCharsets.UTF_8))) { - - String clientFeatures = reader.lines().collect(Collectors.joining("\n")); - - return ClientFeaturesResponse.updated(clientFeatures); + String contentEncoding = request.getHeaderField("Content-Encoding"); + if ("gzip".equalsIgnoreCase(contentEncoding)) { + try (GZIPInputStream stream = new GZIPInputStream(request.getInputStream())) { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int len; + while ((len = stream.read(buffer)) != -1) { + outputStream.write(buffer, 0, len); + } + String clientFeatures = outputStream.toString(StandardCharsets.UTF_8); + return ClientFeaturesResponse.updated(clientFeatures); + } + } + } else { + try (BufferedReader reader = + new BufferedReader( + new InputStreamReader( + (InputStream) request.getContent(), + StandardCharsets.UTF_8))) { + + String clientFeatures = reader.lines().collect(Collectors.joining("\n")); + + return ClientFeaturesResponse.updated(clientFeatures); + } } } else if (followRedirect && (responseCode == HttpURLConnection.HTTP_MOVED_TEMP @@ -114,6 +127,7 @@ private HttpURLConnection openConnection(URL url) throws IOException { connection.setReadTimeout((int) this.config.getFetchTogglesReadTimeout().toMillis()); connection.setRequestProperty("Accept", "application/json"); connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept-Encoding", "gzip,deflate"); UnleashConfig.setRequestProperties(connection, this.config); etag.ifPresent(val -> connection.setRequestProperty("If-None-Match", val)); diff --git a/src/test/java/io/getunleash/HotReloadSchedulerReuseTest.java b/src/test/java/io/getunleash/HotReloadSchedulerReuseTest.java index 530ca4cbc..f93e772d0 100644 --- a/src/test/java/io/getunleash/HotReloadSchedulerReuseTest.java +++ b/src/test/java/io/getunleash/HotReloadSchedulerReuseTest.java @@ -1,25 +1,23 @@ package io.getunleash; -import io.getunleash.util.UnleashConfig; -import org.junit.jupiter.api.*; +import static org.assertj.core.api.Assertions.assertThat; +import io.getunleash.util.UnleashConfig; import java.lang.reflect.Field; import java.util.concurrent.ScheduledThreadPoolExecutor; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.*; class HotReloadSchedulerReuseTest { - private UnleashConfig baseConfig() { return UnleashConfig.builder() - .appName("hot-reload-test-app") - .instanceId("A") - .unleashAPI("http://localhost") // never hit - .synchronousFetchOnInitialisation(false) - .fetchTogglesInterval(100) - .sendMetricsInterval(100) - .build(); + .appName("hot-reload-test-app") + .instanceId("A") + .unleashAPI("http://localhost") // never hit + .synchronousFetchOnInitialisation(false) + .fetchTogglesInterval(100) + .sendMetricsInterval(100) + .build(); } private ScheduledThreadPoolExecutor currentGlobalExecutor() throws Exception { @@ -37,9 +35,7 @@ private ScheduledThreadPoolExecutor currentGlobalExecutor() throws Exception { @Test void secondClientDoesNotReuseSchedulerExecutor() throws Exception { // 1) Create first client; let it schedule background tasks - DefaultUnleash first = new DefaultUnleash( - baseConfig() - ); + DefaultUnleash first = new DefaultUnleash(baseConfig()); // Let it initialize/schedule Thread.sleep(150); @@ -57,11 +53,10 @@ void secondClientDoesNotReuseSchedulerExecutor() throws Exception { assertThat(execAfterShutdown).isNull(); // 3) "Reloaded app": create a second client in the same JVM (statics still around) - DefaultUnleash second = new DefaultUnleash( - baseConfig() - ); + DefaultUnleash second = new DefaultUnleash(baseConfig()); - // 4) Assert that the second client creates a fresh executor (not reusing the terminated one) + // 4) Assert that the second client creates a fresh executor (not reusing the terminated + // one) ScheduledThreadPoolExecutor execUsedBySecond = currentGlobalExecutor(); assertThat(execUsedBySecond).isNotNull(); assertThat(execUsedBySecond.isShutdown()).isFalse(); // it's a new one