This is an automated email from the ASF dual-hosted git repository.

Gabriel39 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 553c23dd340 [fix](regression) Use local HTTP resources in TVF test 
(#65299)
553c23dd340 is described below

commit 553c23dd3405865f81efe645952cda6bd86ffde4
Author: Gabriel <[email protected]>
AuthorDate: Tue Jul 7 15:22:37 2026 +0800

    [fix](regression) Use local HTTP resources in TVF test (#65299)
---
 .../external_table_p0/tvf/test_http_tvf.groovy     | 166 ++++++++++++++++++---
 1 file changed, 149 insertions(+), 17 deletions(-)

diff --git a/regression-test/suites/external_table_p0/tvf/test_http_tvf.groovy 
b/regression-test/suites/external_table_p0/tvf/test_http_tvf.groovy
index 9e8ad46fba1..ad0ffffc853 100644
--- a/regression-test/suites/external_table_p0/tvf/test_http_tvf.groovy
+++ b/regression-test/suites/external_table_p0/tvf/test_http_tvf.groovy
@@ -22,13 +22,142 @@ import com.sun.net.httpserver.HttpExchange
 import java.nio.file.Files
 import java.nio.file.Paths
 import java.net.InetSocketAddress
+import java.net.InetAddress
+import java.net.URLDecoder
 
 suite("test_http_tvf", "p0") {
+    def dataRoot = 
Paths.get(context.config.dataPath).toAbsolutePath().normalize()
+    HttpServer httpServer = HttpServer.create(new InetSocketAddress("0.0.0.0", 
0), 0)
+
+    def writeResponse = { HttpExchange exchange, int status, byte[] body ->
+        exchange.sendResponseHeaders(status, body.length)
+        exchange.responseBody.withCloseable { os ->
+            os.write(body)
+        }
+    }
+
+    def sendRangeNotSatisfiable = { HttpExchange exchange, long fileSize ->
+        exchange.responseHeaders.add("Content-Range", "bytes */${fileSize}")
+        exchange.sendResponseHeaders(416, -1)
+        exchange.close()
+    }
+
+    def copyRange = { inputStream, outputStream, long length ->
+        byte[] buffer = new byte[8192]
+        long remaining = length
+        while (remaining > 0) {
+            int readSize = inputStream.read(buffer, 0, (int) 
Math.min(buffer.length, remaining))
+            if (readSize < 0) {
+                break
+            }
+            outputStream.write(buffer, 0, readSize)
+            remaining -= readSize
+        }
+    }
+
+    def skipFully = { inputStream, long length ->
+        long remaining = length
+        while (remaining > 0) {
+            long skipped = inputStream.skip(remaining)
+            if (skipped <= 0) {
+                if (inputStream.read() < 0) {
+                    break
+                }
+                skipped = 1
+            }
+            remaining -= skipped
+        }
+    }
+
+    httpServer.createContext("/", { HttpExchange exchange ->
+        if (!"GET".equalsIgnoreCase(exchange.requestMethod) && 
!"HEAD".equalsIgnoreCase(exchange.requestMethod)) {
+            writeResponse(exchange, 405, "Method Not 
Allowed".getBytes("UTF-8"))
+            return
+        }
+
+        def requestPath = URLDecoder.decode(exchange.requestURI.path, "UTF-8")
+        def relativePath = requestPath.startsWith("/") ? 
requestPath.substring(1) : requestPath
+        def filePath = dataRoot.resolve(relativePath).normalize()
+        if (!filePath.startsWith(dataRoot)) {
+            writeResponse(exchange, 403, "Forbidden".getBytes("UTF-8"))
+            return
+        }
+        if (!Files.isRegularFile(filePath)) {
+            writeResponse(exchange, 404, "Not Found".getBytes("UTF-8"))
+            return
+        }
+
+        long fileSize = Files.size(filePath)
+        exchange.responseHeaders.add("Accept-Ranges", "bytes")
+        exchange.responseHeaders.add("Content-Type", 
"application/octet-stream")
+
+        long start = 0
+        long end = fileSize - 1
+        int status = 200
+        String rangeHeader = exchange.requestHeaders.getFirst("Range")
+        if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
+            String range = rangeHeader.substring("bytes=".length()).split(",", 
2)[0].trim()
+            try {
+                if (range.startsWith("-")) {
+                    long suffixLength = Long.parseLong(range.substring(1))
+                    if (suffixLength <= 0) {
+                        sendRangeNotSatisfiable(exchange, fileSize)
+                        return
+                    }
+                    start = Math.max(0, fileSize - suffixLength)
+                } else {
+                    String[] parts = range.split("-", 2)
+                    start = Long.parseLong(parts[0])
+                    if (parts.length > 1 && parts[1].length() > 0) {
+                        end = Long.parseLong(parts[1])
+                    }
+                }
+                if (start < 0 || start >= fileSize || end < start) {
+                    sendRangeNotSatisfiable(exchange, fileSize)
+                    return
+                }
+                end = Math.min(end, fileSize - 1)
+                status = 206
+                exchange.responseHeaders.add("Content-Range", "bytes 
${start}-${end}/${fileSize}")
+            } catch (NumberFormatException e) {
+                sendRangeNotSatisfiable(exchange, fileSize)
+                return
+            }
+        }
+
+        long responseLength = fileSize == 0 ? 0 : end - start + 1
+        exchange.responseHeaders.add("Content-Length", 
Long.toString(responseLength))
+        exchange.sendResponseHeaders(status, 
"HEAD".equalsIgnoreCase(exchange.requestMethod) ? -1 : responseLength)
+        if ("HEAD".equalsIgnoreCase(exchange.requestMethod)) {
+            exchange.close()
+            return
+        }
+        Files.newInputStream(filePath).withCloseable { input ->
+            skipFully(input, start)
+            exchange.responseBody.withCloseable { output ->
+                copyRange(input, output, responseLength)
+            }
+        }
+    } as HttpHandler)
+    httpServer.start()
+
+    String httpServerHost = context.config.otherConfigs.get("httpTvfHost")
+    if (httpServerHost == null || httpServerHost.trim().isEmpty()) {
+        httpServerHost = context.config.otherConfigs.get("externalEnvIp")
+    }
+    if (httpServerHost == null || httpServerHost.trim().isEmpty()) {
+        httpServerHost = InetAddress.getLocalHost().getHostAddress()
+    }
+    String httpBaseUrl = "http://${httpServerHost}:${httpServer.address.port}";
+    def httpUrl = { String relativePath -> "${httpBaseUrl}/${relativePath}" }
+    logger.info("Start local HTTP server for http tvf test: ${httpBaseUrl}, 
root: ${dataRoot}")
+
+    try {
     // csv
     qt_sql01 """
         SELECT *
         FROM http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/http_stream/all_types.csv";,
+            "uri" = "${httpUrl("load_p0/http_stream/all_types.csv")}",
             "format" = "csv",
             "column_separator" = ","
         )
@@ -38,7 +167,7 @@ suite("test_http_tvf", "p0") {
     qt_sql02 """
         SELECT count(*)
         FROM http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/http_stream/all_types.csv";,
+            "uri" = "${httpUrl("load_p0/http_stream/all_types.csv")}",
             "format" = "csv",
             "column_separator" = ","
         );
@@ -47,7 +176,7 @@ suite("test_http_tvf", "p0") {
     qt_sql03 """
         desc function
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/http_stream/all_types.csv";,
+            "uri" = "${httpUrl("load_p0/http_stream/all_types.csv")}",
             "format" = "csv",
             "column_separator" = ","
         );
@@ -56,7 +185,7 @@ suite("test_http_tvf", "p0") {
     qt_sql04 """
         desc function
         file(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/http_stream/all_types.csv";,
+            "uri" = "${httpUrl("load_p0/http_stream/all_types.csv")}",
             "format" = "csv",
             "fs.http.support" = "true",
             "column_separator" = ","
@@ -67,7 +196,7 @@ suite("test_http_tvf", "p0") {
     qt_sql05 """
         desc function
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/all_types.csv.gz";,
+            "uri" = "${httpUrl("load_p0/stream_load/all_types.csv.gz")}",
             "format" = "csv",
             "column_separator" = ",",
             "compress_type" = "gz"
@@ -77,7 +206,7 @@ suite("test_http_tvf", "p0") {
     qt_sql05 """
         select count(*) from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/all_types.csv.gz";,
+            "uri" = "${httpUrl("load_p0/stream_load/all_types.csv.gz")}",
             "format" = "csv",
             "column_separator" = ",",
             "compress_type" = "gz"
@@ -88,7 +217,7 @@ suite("test_http_tvf", "p0") {
     qt_sql06 """
         select count(*) from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/basic_data.json";,
+            "uri" = "${httpUrl("load_p0/stream_load/basic_data.json")}",
             "format" = "json",
             "strip_outer_array" = true
         );
@@ -97,7 +226,7 @@ suite("test_http_tvf", "p0") {
     qt_sql07 """
         desc function
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/basic_data.json";,
+            "uri" = "${httpUrl("load_p0/stream_load/basic_data.json")}",
             "format" = "json",
             "strip_outer_array" = true
         );
@@ -107,7 +236,7 @@ suite("test_http_tvf", "p0") {
     qt_sql08 """
         select * from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/external_table_p0/tvf/t.parquet";,
+            "uri" = "${httpUrl("external_table_p0/tvf/t.parquet")}",
             "format" = "parquet"
         ) order by id limit 10;
     """
@@ -115,7 +244,7 @@ suite("test_http_tvf", "p0") {
     qt_sql09 """
         select arr_map, id from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/external_table_p0/tvf/t.parquet";,
+            "uri" = "${httpUrl("external_table_p0/tvf/t.parquet")}",
             "format" = "parquet"
         ) order by id limit 10;
     """
@@ -123,7 +252,7 @@ suite("test_http_tvf", "p0") {
     qt_sql10 """
         desc function
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/external_table_p0/tvf/t.parquet";,
+            "uri" = "${httpUrl("external_table_p0/tvf/t.parquet")}",
             "format" = "parquet"
         );
     """
@@ -131,7 +260,7 @@ suite("test_http_tvf", "p0") {
     qt_sql11 """
         select m, id from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/types/complex_types/mm.orc";,
+            "uri" = "${httpUrl("types/complex_types/mm.orc")}",
             "format" = "orc"
         ) order by id limit 10;
     """
@@ -139,7 +268,7 @@ suite("test_http_tvf", "p0") {
     qt_sql12 """
         desc function
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/types/complex_types/mm.orc";,
+            "uri" = "${httpUrl("types/complex_types/mm.orc")}",
             "format" = "orc"
         );
     """
@@ -149,7 +278,7 @@ suite("test_http_tvf", "p0") {
         sql """
             select * from
             http(
-                "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/test_decimal.parquet";,
+                "uri" = 
"${httpUrl("load_p0/stream_load/test_decimal.parquet")}",
                 "format" = "parquet",
                 "http.enable.range.request" = "false",
                 "http.max.request.size.bytes" = "1000"
@@ -162,7 +291,7 @@ suite("test_http_tvf", "p0") {
     qt_sql_norange """
         SELECT count(1) FROM
         HTTP(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/tags/4.0.2-rc02/regression-test/data/datatype_p0/nested_types/query/test_nested_type_with_resize.csv";,
+            "uri" = 
"${httpUrl("datatype_p0/nested_types/query/test_nested_type_with_resize.csv")}",
             "format" = "csv",
             "http.enable.range.request"="false"
         );
@@ -171,7 +300,7 @@ suite("test_http_tvf", "p0") {
     qt_sql13 """
         select * from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/test_decimal.parquet";,
+            "uri" = "${httpUrl("load_p0/stream_load/test_decimal.parquet")}",
             "format" = "parquet",
             "http.enable.range.request" = "true",
             "http.max.request.size.bytes" = "1000"
@@ -181,7 +310,7 @@ suite("test_http_tvf", "p0") {
     qt_sql14 """
         select * from
         http(
-            "uri" = 
"https://raw.githubusercontent.com/apache/doris/refs/heads/master/regression-test/data/load_p0/stream_load/test_decimal.parquet";,
+            "uri" = "${httpUrl("load_p0/stream_load/test_decimal.parquet")}",
             "format" = "parquet",
             "http.enable.range.request" = "true",
             "http.max.request.size.bytes" = "2000"
@@ -256,4 +385,7 @@ suite("test_http_tvf", "p0") {
             "format" = "parquet"
         ) order by text limit 1;
     """
+    } finally {
+        httpServer.stop(0)
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to