Skip to content

Commit 088006f

Browse files
committed
Use ephemeral port for Hazelcast
When Hazelcast is started on a fixed port and that port is already in use, it does not fail to start which makes the problem hard to detect. A symptom of the problem is that clients will not be able to connect and will either retry indefinitely or will timeout depending on their configuration. This commit updates the Hazelcast client tests to start the Hazelcast instance on an ephemeral port and to customize the client configuration with the instance's address before use. This should allow the client tests to work reliably in an environment where Hazelcast's default port is already in use. Closes gh-35903
1 parent 6397897 commit 088006f

File tree

5 files changed

+87
-63
lines changed

5 files changed

+87
-63
lines changed

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/hazelcast/HazelcastAutoConfigurationClientTests.java

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@
1616

1717
package org.springframework.boot.autoconfigure.hazelcast;
1818

19+
import java.io.File;
20+
import java.io.FileReader;
21+
import java.io.FileWriter;
22+
import java.io.IOException;
23+
import java.net.InetSocketAddress;
24+
import java.net.MalformedURLException;
25+
import java.nio.file.Files;
26+
1927
import com.hazelcast.client.HazelcastClient;
2028
import com.hazelcast.client.config.ClientConfig;
21-
import com.hazelcast.client.config.ClientConnectionStrategyConfig;
22-
import com.hazelcast.client.config.ConnectionRetryConfig;
2329
import com.hazelcast.client.impl.clientside.HazelcastClientProxy;
2430
import com.hazelcast.config.Config;
2531
import com.hazelcast.core.Hazelcast;
@@ -36,6 +42,7 @@
3642
import org.springframework.boot.test.context.runner.ContextConsumer;
3743
import org.springframework.context.annotation.Bean;
3844
import org.springframework.context.annotation.Configuration;
45+
import org.springframework.util.FileCopyUtils;
3946

4047
import static org.assertj.core.api.Assertions.assertThat;
4148

@@ -52,9 +59,15 @@ class HazelcastAutoConfigurationClientTests {
5259
*/
5360
private static HazelcastInstance hazelcastServer;
5461

62+
private static String endpointAddress;
63+
5564
@BeforeAll
5665
static void init() {
57-
hazelcastServer = Hazelcast.newHazelcastInstance();
66+
Config config = Config.load();
67+
config.getNetworkConfig().setPort(0);
68+
hazelcastServer = Hazelcast.newHazelcastInstance(config);
69+
InetSocketAddress inetSocketAddress = (InetSocketAddress) hazelcastServer.getLocalEndpoint().getSocketAddress();
70+
endpointAddress = inetSocketAddress.getHostString() + ":" + inetSocketAddress.getPort();
5871
}
5972

6073
@AfterAll
@@ -69,73 +82,52 @@ static void close() {
6982

7083
@Test
7184
void systemPropertyWithXml() {
85+
File config = prepareConfiguration("src/test/resources/org/springframework/"
86+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml");
7287
this.contextRunner
73-
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY
74-
+ "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml")
88+
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + "=" + config.getAbsolutePath())
7589
.run(assertSpecificHazelcastClient("explicit-xml"));
7690
}
7791

7892
@Test
7993
void systemPropertyWithYaml() {
94+
File config = prepareConfiguration("src/test/resources/org/springframework/"
95+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml");
8096
this.contextRunner
81-
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY
82-
+ "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml")
97+
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + "=" + config.getAbsolutePath())
8398
.run(assertSpecificHazelcastClient("explicit-yaml"));
8499
}
85100

86101
@Test
87102
void systemPropertyWithYml() {
103+
File config = prepareConfiguration("src/test/resources/org/springframework/"
104+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yml");
88105
this.contextRunner
89-
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY
90-
+ "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.yml")
91-
.run(assertSpecificHazelcastClient("explicit-yml"));
92-
}
93-
94-
@Test
95-
void explicitConfigFileWithXml() {
96-
this.contextRunner
97-
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
98-
+ "hazelcast/hazelcast-client-specific.xml")
99-
.run(assertSpecificHazelcastClient("explicit-xml"));
100-
}
101-
102-
@Test
103-
void explicitConfigFileWithYaml() {
104-
this.contextRunner
105-
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
106-
+ "hazelcast/hazelcast-client-specific.yaml")
107-
.run(assertSpecificHazelcastClient("explicit-yaml"));
108-
}
109-
110-
@Test
111-
void explicitConfigFileWithYml() {
112-
this.contextRunner
113-
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
114-
+ "hazelcast/hazelcast-client-specific.yml")
106+
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + "=" + config.getAbsolutePath())
115107
.run(assertSpecificHazelcastClient("explicit-yml"));
116108
}
117109

118110
@Test
119-
void explicitConfigUrlWithXml() {
120-
this.contextRunner
121-
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
122-
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml")
111+
void explicitConfigUrlWithXml() throws MalformedURLException {
112+
File config = prepareConfiguration("src/test/resources/org/springframework/"
113+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml");
114+
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
123115
.run(assertSpecificHazelcastClient("explicit-xml"));
124116
}
125117

126118
@Test
127-
void explicitConfigUrlWithYaml() {
128-
this.contextRunner
129-
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
130-
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml")
119+
void explicitConfigUrlWithYaml() throws MalformedURLException {
120+
File config = prepareConfiguration("src/test/resources/org/springframework/"
121+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml");
122+
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
131123
.run(assertSpecificHazelcastClient("explicit-yaml"));
132124
}
133125

134126
@Test
135-
void explicitConfigUrlWithYml() {
136-
this.contextRunner
137-
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
138-
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yml")
127+
void explicitConfigUrlWithYml() throws MalformedURLException {
128+
File config = prepareConfiguration("src/test/resources/org/springframework/"
129+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yml");
130+
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
139131
.run(assertSpecificHazelcastClient("explicit-yml"));
140132
}
141133

@@ -156,28 +148,26 @@ void clientConfigTakesPrecedence() {
156148
}
157149

158150
@Test
159-
void clientConfigWithInstanceNameCreatesClientIfNecessary() {
151+
void clientConfigWithInstanceNameCreatesClientIfNecessary() throws MalformedURLException {
160152
assertThat(HazelcastClient.getHazelcastClientByName("spring-boot")).isNull();
161-
this.contextRunner
162-
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
163-
+ "boot/autoconfigure/hazelcast/hazelcast-client-instance.xml")
153+
File config = prepareConfiguration("src/test/resources/org/springframework/"
154+
+ "boot/autoconfigure/hazelcast/hazelcast-client-instance.xml");
155+
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
164156
.run((context) -> assertThat(context).getBean(HazelcastInstance.class)
165157
.extracting(HazelcastInstance::getName)
166158
.isEqualTo("spring-boot"));
167159
}
168160

169161
@Test
170-
void autoConfiguredClientConfigUsesApplicationClassLoader() {
171-
this.contextRunner
172-
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
173-
+ "hazelcast/hazelcast-client-specific.xml")
174-
.run((context) -> {
175-
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
176-
assertThat(hazelcast).isInstanceOf(HazelcastClientProxy.class);
177-
ClientConfig clientConfig = ((HazelcastClientProxy) hazelcast).getClientConfig();
178-
assertThat(clientConfig.getClassLoader())
179-
.isSameAs(context.getSourceApplicationContext().getClassLoader());
180-
});
162+
void autoConfiguredClientConfigUsesApplicationClassLoader() throws MalformedURLException {
163+
File config = prepareConfiguration("src/test/resources/org/springframework/"
164+
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml");
165+
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL()).run((context) -> {
166+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
167+
assertThat(hazelcast).isInstanceOf(HazelcastClientProxy.class);
168+
ClientConfig clientConfig = ((HazelcastClientProxy) hazelcast).getClientConfig();
169+
assertThat(clientConfig.getClassLoader()).isSameAs(context.getSourceApplicationContext().getClassLoader());
170+
});
181171
}
182172

183173
private ContextConsumer<AssertableApplicationContext> assertSpecificHazelcastClient(String label) {
@@ -193,6 +183,22 @@ private static Condition<HazelcastInstance> labelEqualTo(String label) {
193183
.anyMatch((e) -> e.equals(label)), "Label equals to " + label);
194184
}
195185

186+
private File prepareConfiguration(String input) {
187+
File configFile = new File(input);
188+
try {
189+
String config = FileCopyUtils.copyToString(new FileReader(configFile));
190+
config = config.replace("${address}", endpointAddress);
191+
System.out.println(config);
192+
File outputFile = new File(Files.createTempDirectory(getClass().getSimpleName()).toFile(),
193+
configFile.getName());
194+
FileCopyUtils.copy(config, new FileWriter(outputFile));
195+
return outputFile;
196+
}
197+
catch (IOException ex) {
198+
throw new RuntimeException(ex);
199+
}
200+
}
201+
196202
@Configuration(proxyBeanMethods = false)
197203
static class HazelcastServerAndClientConfig {
198204

@@ -203,8 +209,10 @@ Config config() {
203209

204210
@Bean
205211
ClientConfig clientConfig() {
206-
return new ClientConfig().setConnectionStrategyConfig(new ClientConnectionStrategyConfig()
207-
.setConnectionRetryConfig(new ConnectionRetryConfig().setClusterConnectTimeoutMillis(60000)));
212+
ClientConfig config = new ClientConfig();
213+
config.getConnectionStrategyConfig().getConnectionRetryConfig().setClusterConnectTimeoutMillis(60000);
214+
config.getNetworkConfig().getAddresses().add(endpointAddress);
215+
return config;
208216
}
209217

210218
}

spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-instance.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,11 @@
1010
<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>
1111
</connection-retry>
1212
</connection-strategy>
13+
14+
<network>
15+
<cluster-members>
16+
<address>${address}</address>
17+
</cluster-members>
18+
</network>
1319

1420
</hazelcast-client>

spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@
1010
<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>
1111
</connection-retry>
1212
</connection-strategy>
13-
13+
<network>
14+
<cluster-members>
15+
<address>${address}</address>
16+
</cluster-members>
17+
</network>
1418
</hazelcast-client>

spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ hazelcast-client:
44
connection-strategy:
55
connection-retry:
66
cluster-connect-timeout-millis: 60000
7+
network:
8+
cluster-members:
9+
- ${address}

spring-boot-project/spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ hazelcast-client:
44
connection-strategy:
55
connection-retry:
66
cluster-connect-timeout-millis: 60000
7+
network:
8+
cluster-members:
9+
- ${address}

0 commit comments

Comments
 (0)