This is an automated email from the ASF dual-hosted git repository.
davidzollo pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git
The following commit(s) were added to refs/heads/dev by this push:
new 3a8a88d381 [Test][Zeta] Stabilize HTTPS REST API test (#11203)
3a8a88d381 is described below
commit 3a8a88d38158d13a6f3cabe9e6d2cbc16675cab7
Author: Daniel <[email protected]>
AuthorDate: Sun Aug 23 16:13:30 2026 +0800
[Test][Zeta] Stabilize HTTPS REST API test (#11203)
Co-authored-by: DanielLeens <[email protected]>
---
.../engine/server/rest/RestApiHttpsTest.java | 116 +++++++++++++--------
1 file changed, 74 insertions(+), 42 deletions(-)
diff --git
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
index f9d5ebae7e..0cd37b4244 100644
---
a/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
+++
b/seatunnel-engine/seatunnel-engine-server/src/test/java/org/apache/seatunnel/engine/server/rest/RestApiHttpsTest.java
@@ -47,9 +47,13 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;
import java.io.BufferedReader;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
+import java.net.ServerSocket;
+import java.nio.file.Paths;
import java.util.Collections;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -59,13 +63,12 @@ import static org.junit.Assert.assertEquals;
/** Test for Rest API with HTTPS. */
@DisabledOnOs(OS.WINDOWS)
public class RestApiHttpsTest extends AbstractSeaTunnelServerTest {
- private static final int HTTP_PORT = 28080;
- private static final int HTTPS_PORT = 28443;
-
- private static final int HTTP_PORT2 = 28088;
- private static final int HTTPS_PORT2 = 28543;
private static final String SERVER_KEYSTORE_PASSWORD =
"server_keystore_password";
private static final String CLIENT_KEYSTORE_PASSWORD =
"client_keystore_password";
+ private final int httpPort = randomAvailablePort();
+ private final int httpsPort = randomAvailablePort();
+ private final int httpPort2 = randomAvailablePort();
+ private final int httpsPort2 = randomAvailablePort();
@Override
@BeforeAll
@@ -79,8 +82,8 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
HttpConfig httpConfig =
seaTunnelConfig.getEngineConfig().getHttpConfig();
httpConfig.setEnabled(true);
- httpConfig.setPort(HTTP_PORT);
- httpConfig.setHttpsPort(HTTPS_PORT);
+ httpConfig.setPort(httpPort);
+ httpConfig.setHttpsPort(httpsPort);
httpConfig.setEnableHttps(true);
httpConfig.setKeyStorePath(getPath("server_keystore.jks"));
@@ -94,13 +97,25 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
}
public String getPath(String confFile) {
- return System.getProperty("user.dir") + "/src/test/resources/https/" +
confFile;
+ try {
+ return Paths.get(
+ Objects.requireNonNull(
+ getClass()
+ .getClassLoader()
+ .getResource("https/" +
confFile),
+ "Missing HTTPS test resource: " +
confFile)
+ .toURI())
+ .toString();
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Failed to resolve HTTPS test resource: " + confFile, e);
+ }
}
@Test
public void testRestApiHttp() throws Exception {
restApiRequestHttp(
- "http://localhost:" + HTTP_PORT + "/overview",
+ "http://localhost:" + httpPort + "/overview",
(code, content) -> {
Assertions.assertEquals(200, code);
Assertions.assertTrue(content.contains("projectVersion"));
@@ -114,7 +129,7 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
HttpsURLConnection conn =
(HttpsURLConnection)
- new java.net.URL("https://localhost:" + HTTPS_PORT +
"/overview")
+ new java.net.URL("https://localhost:" + httpsPort +
"/overview")
.openConnection();
conn.setSSLSocketFactory(sslContext.getSocketFactory());
@@ -133,7 +148,7 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
SSLHandshakeException.class,
() -> {
java.net.URL url =
- new java.net.URL("https://localhost:" + HTTPS_PORT
+ "/overview");
+ new java.net.URL("https://localhost:" + httpsPort
+ "/overview");
HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
conn.getResponseCode();
});
@@ -164,7 +179,7 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
// pagination test
// page 1
restApiRequestHttp(
- "http://localhost:" + HTTP_PORT2 +
"/finished-jobs?page=1&rows=" + pageSize,
+ "http://localhost:" + httpPort2 +
"/finished-jobs?page=1&rows=" + pageSize,
(code, content) -> {
Assertions.assertEquals(200, code);
JsonObject resultJson = (JsonObject) Json.parse(content);
@@ -176,7 +191,7 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
});
// page 2
restApiRequestHttp(
- "http://localhost:" + HTTP_PORT2 +
"/finished-jobs?page=2&rows=" + pageSize,
+ "http://localhost:" + httpPort2 +
"/finished-jobs?page=2&rows=" + pageSize,
(code, content) -> {
Assertions.assertEquals(200, code);
JsonObject resultJson = (JsonObject) Json.parse(content);
@@ -188,7 +203,7 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
});
// no pagination test
restApiRequestHttp(
- "http://localhost:" + HTTP_PORT2 + "/finished-jobs",
+ "http://localhost:" + httpPort2 + "/finished-jobs",
(code, content) -> {
Assertions.assertEquals(200, code);
JsonArray resultJson = (JsonArray) Json.parse(content);
@@ -220,9 +235,10 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
.getRunningJobMetrics()
.size()));
- // pagination test
- restApiRequestHttp(
- "http://localhost:" + HTTP_PORT2 +
"/running-jobs?page=1&rows=" + pageSize,
+ // Wait for the REST view itself because the running metrics map can
become visible
+ // slightly earlier than the paginated HTTP response under CI load.
+ awaitRestApiRequestHttp(
+ "http://localhost:" + httpPort2 + "/running-jobs?page=1&rows="
+ pageSize,
(code, content) -> {
Assertions.assertEquals(200, code);
JsonObject resultJson = (JsonObject) Json.parse(content);
@@ -233,8 +249,8 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
Assertions.assertTrue(total == jobNum && data.size() ==
pageSize);
});
// no pagination test
- restApiRequestHttp(
- "http://localhost:" + HTTP_PORT2 + "/running-jobs",
+ awaitRestApiRequestHttp(
+ "http://localhost:" + httpPort2 + "/running-jobs",
(code, content) -> {
Assertions.assertEquals(200, code);
JsonArray resultJson = (JsonArray) Json.parse(content);
@@ -266,8 +282,8 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
.getJobCountMetrics()
.getFinishedJobCount()));
- restApiRequestHttp(
- "http://localhost:" + HTTP_PORT2 +
"/finished-jobs?page=10&rows=" + pageSize,
+ awaitRestApiRequestHttp(
+ "http://localhost:" + httpPort2 +
"/finished-jobs?page=10&rows=" + pageSize,
(code, content) -> {
Assertions.assertEquals(400, code);
Assertions.assertTrue(content.contains("Page number
exceeds total pages"));
@@ -275,28 +291,35 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
shutdown(jobInformation);
}
+ private void awaitRestApiRequestHttp(String url, RestApiRequestCallback
callback) {
+ await().atMost(60, TimeUnit.SECONDS)
+ .pollInterval(200, TimeUnit.MILLISECONDS)
+ .untilAsserted(() -> restApiRequestHttp(url, callback));
+ }
+
private void restApiRequestHttp(String url, RestApiRequestCallback
callback) throws Exception {
HttpURLConnection conn = (HttpURLConnection) new
java.net.URL(url).openConnection();
- if (conn.getResponseCode() != 200) {
- try (BufferedReader in =
- new BufferedReader(new
InputStreamReader(conn.getErrorStream()))) {
- String response = in.lines().collect(Collectors.joining());
- if (callback != null) {
- callback.callback(conn.getResponseCode(), response);
- }
- } finally {
- conn.disconnect();
- }
- } else {
- try (BufferedReader in =
- new BufferedReader(new
InputStreamReader(conn.getInputStream()))) {
- String response = in.lines().collect(Collectors.joining());
- if (callback != null) {
- callback.callback(conn.getResponseCode(), response);
- }
- } finally {
- conn.disconnect();
+ try {
+ int responseCode = conn.getResponseCode();
+ String response = readResponseBody(conn, responseCode);
+ if (callback != null) {
+ callback.callback(responseCode, response);
}
+ } finally {
+ conn.disconnect();
+ }
+ }
+
+ private String readResponseBody(HttpURLConnection conn, int responseCode)
throws Exception {
+ InputStream responseStream =
+ responseCode >= HttpURLConnection.HTTP_BAD_REQUEST
+ ? conn.getErrorStream()
+ : conn.getInputStream();
+ if (responseStream == null) {
+ return "";
+ }
+ try (BufferedReader in = new BufferedReader(new
InputStreamReader(responseStream))) {
+ return in.lines().collect(Collectors.joining());
}
}
@@ -336,8 +359,8 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
HttpConfig httpConfig =
seaTunnelConfig.getEngineConfig().getHttpConfig();
httpConfig.setEnabled(true);
- httpConfig.setPort(HTTP_PORT2);
- httpConfig.setHttpsPort(HTTPS_PORT2);
+ httpConfig.setPort(httpPort2);
+ httpConfig.setHttpsPort(httpsPort2);
httpConfig.setEnableHttps(false);
HazelcastInstanceImpl healcastInstance =
@@ -359,6 +382,15 @@ public class RestApiHttpsTest extends
AbstractSeaTunnelServerTest {
}
}
+ private int randomAvailablePort() {
+ try (ServerSocket socket = new ServerSocket(0)) {
+ socket.setReuseAddress(true);
+ return socket.getLocalPort();
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to allocate a free test
port", e);
+ }
+ }
+
private static class JobInformation {
public final HazelcastInstanceImpl healcastInstance;