Skip to content

Commit 209deba

Browse files
committed
GEODE-10556: Fix race condition in PulseSecurityWithSSLTest
Add multi-stage synchronization with delay to handle JMX authentication backend initialization on slower CI runners. Changes: 1. Wait for ManagementService and MemberMXBean initialization 2. Wait for Pulse web application to respond (with proper entity cleanup) 3. Add 2-second delay before authentication to allow backend readiness 4. Add debug logging to diagnose initialization timing Fixes connection pool exhaustion by properly consuming HTTP response entities in await loops. Uses a simple delay instead of retry loop to avoid blocking all available connections.
1 parent 3b21ac6 commit 209deba

1 file changed

Lines changed: 81 additions & 2 deletions

File tree

geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseSecurityWithSSLTest.java

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS;
3737
import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
3838
import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
39+
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
3940
import static org.apache.geode.test.util.ResourceUtils.createTempFileFromResource;
4041
import static org.assertj.core.api.Assertions.assertThat;
4142

@@ -51,6 +52,7 @@
5152
import org.junit.experimental.categories.Category;
5253

5354
import org.apache.geode.examples.SimpleSecurityManager;
55+
import org.apache.geode.management.ManagementService;
5456
import org.apache.geode.security.SecurableCommunicationChannels;
5557
import org.apache.geode.test.junit.categories.PulseTest;
5658
import org.apache.geode.test.junit.categories.SecurityTest;
@@ -83,13 +85,53 @@ public void loginWithIncorrectAndThenCorrectPassword() throws Exception {
8385

8486
locator.withSecurityManager(SimpleSecurityManager.class).withProperties(securityProps)
8587
.startLocator();
86-
88+
System.out.println("[DEBUG] Locator started on port: " + locator.getHttpPort());
89+
90+
// Wait for JMX/Management Service to be fully initialized before login attempts
91+
// This prevents race conditions on slower CI machines where authentication may fail
92+
// if the JMX backend is not ready yet
93+
ManagementService service =
94+
ManagementService.getExistingManagementService(locator.getLocator().getCache());
95+
System.out.println("[DEBUG] ManagementService obtained, waiting for MemberMXBean...");
96+
await()
97+
.untilAsserted(() -> assertThat(service.getMemberMXBean()).isNotNull());
98+
System.out.println("[DEBUG] MemberMXBean is ready: " + service.getMemberMXBean());
99+
100+
// Additionally wait for Pulse web application to be fully responsive
101+
System.out.println("[DEBUG] Waiting for Pulse web app to respond...");
102+
await()
103+
.untilAsserted(() -> {
104+
ClassicHttpResponse loginPageResponse = client.get("/pulse/login.html");
105+
try {
106+
assertThat(loginPageResponse.getCode()).isEqualTo(200);
107+
} finally {
108+
// Ensure entity is consumed to return connection to pool
109+
if (loginPageResponse.getEntity() != null) {
110+
try {
111+
loginPageResponse.getEntity().getContent().close();
112+
} catch (Exception ignore) {
113+
}
114+
}
115+
}
116+
});
117+
System.out.println("[DEBUG] Pulse web app is responsive");
118+
119+
System.out.println("[DEBUG] Attempting login with wrong password...");
87120
ClassicHttpResponse response = client.loginToPulse("data", "wrongPassword");
121+
System.out.println("[DEBUG] Wrong password response: " + response.getCode() + ", Location: "
122+
+ (response.getFirstHeader("Location") != null
123+
? response.getFirstHeader("Location").getValue() : "null"));
88124
assertThat(response.getCode()).isEqualTo(302);
89125
assertThat(response.getFirstHeader("Location").getValue())
90126
.contains("/pulse/login.html?error=BAD_CREDS");
91127

128+
// Add small delay to ensure backend is ready before login attempt
129+
System.out.println("[DEBUG] Waiting 2 seconds for authentication backend...");
130+
Thread.sleep(2000);
131+
132+
System.out.println("[DEBUG] Attempting login with correct credentials (cluster/cluster)...");
92133
client.loginToPulseAndVerify("cluster", "cluster");
134+
System.out.println("[DEBUG] Login successful!");
93135

94136
// Ensure that the backend JMX connection is working too
95137
response = client.post("/pulse/pulseUpdate", "pulseData",
@@ -122,8 +164,45 @@ public void loginWithDeprecatedSSLOptions() throws Exception {
122164

123165
locator.withSecurityManager(SimpleSecurityManager.class).withProperties(securityProps)
124166
.startLocator();
125-
167+
System.out
168+
.println("[DEBUG] Locator started (deprecated SSL) on port: " + locator.getHttpPort());
169+
170+
// Wait for JMX/Management Service to be fully initialized before login attempts
171+
// This prevents race conditions on slower CI machines where authentication may fail
172+
// if the JMX backend is not ready yet
173+
ManagementService service =
174+
ManagementService.getExistingManagementService(locator.getLocator().getCache());
175+
System.out.println("[DEBUG] ManagementService obtained, waiting for MemberMXBean...");
176+
await()
177+
.untilAsserted(() -> assertThat(service.getMemberMXBean()).isNotNull());
178+
System.out.println("[DEBUG] MemberMXBean is ready: " + service.getMemberMXBean());
179+
180+
// Additionally wait for Pulse web application to be fully responsive
181+
System.out.println("[DEBUG] Waiting for Pulse web app to respond...");
182+
await()
183+
.untilAsserted(() -> {
184+
ClassicHttpResponse loginPageResponse = client.get("/pulse/login.html");
185+
try {
186+
assertThat(loginPageResponse.getCode()).isEqualTo(200);
187+
} finally {
188+
// Ensure entity is consumed to return connection to pool
189+
if (loginPageResponse.getEntity() != null) {
190+
try {
191+
loginPageResponse.getEntity().getContent().close();
192+
} catch (Exception ignore) {
193+
}
194+
}
195+
}
196+
});
197+
System.out.println("[DEBUG] Pulse web app is responsive");
198+
199+
// Add small delay to ensure backend is ready before login attempt
200+
System.out.println("[DEBUG] Waiting 2 seconds for authentication backend...");
201+
Thread.sleep(2000);
202+
203+
System.out.println("[DEBUG] Attempting login with correct credentials (cluster/cluster)...");
126204
client.loginToPulseAndVerify("cluster", "cluster");
205+
System.out.println("[DEBUG] Login successful!");
127206

128207
// Ensure that the backend JMX connection is working too
129208
ClassicHttpResponse response = client.post("/pulse/pulseUpdate", "pulseData",

0 commit comments

Comments
 (0)