Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,20 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.26.3</version>
<version>3.27.6</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.8.1</version>
<version>5.20.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.35.2</version>
<version>3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -177,6 +177,13 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down Expand Up @@ -219,7 +226,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<version>0.8.13</version>
<executions>
<execution>
<id>prepare-agent</id>
Expand Down Expand Up @@ -410,6 +417,9 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<configuration>
<argLine>@{argLine} -javaagent:${org.mockito:mockito-core:jar}</argLine>
</configuration>
</plugin>
</plugins>
</reporting>
Expand Down
40 changes: 27 additions & 13 deletions src/main/java/io/getunleash/repository/HttpFeatureFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down
33 changes: 14 additions & 19 deletions src/test/java/io/getunleash/HotReloadSchedulerReuseTest.java
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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);
Expand All @@ -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
Expand Down
Loading