From 2834f0e4694363321e4b701ce72c6a2d5fdc2e4b Mon Sep 17 00:00:00 2001 From: Pedro Matias Date: Mon, 23 Feb 2026 00:48:52 +0000 Subject: [PATCH 1/6] Intermediate commit --- .../arrow/flight/grpc/NettyClientBuilder.java | 4 +- .../arrow/driver/jdbc/ConnectionTest.java | 114 ++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java b/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java index e658711214..65ecb51ad8 100644 --- a/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java +++ b/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java @@ -139,7 +139,9 @@ public NettyChannelBuilder build() { case LocationSchemes.GRPC_INSECURE: case LocationSchemes.GRPC_TLS: { - builder = NettyChannelBuilder.forAddress(location.toSocketAddress()); + builder = + NettyChannelBuilder.forAddress( + location.getUri().getHost(), location.getUri().getPort()); break; } case LocationSchemes.GRPC_DOMAIN_SOCKET: diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java index 55722f60fb..3369b45f20 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java @@ -768,4 +768,118 @@ public void testResultSetsFromDatabaseMetadataClosedOnConnectionClose() throws E assertTrue(resultSets[i].isClosed()); } } + + /** + * Test that JDBC driver respects JVM proxy settings. + * + *

This test verifies that when JVM proxy properties are set, the Flight client attempts to + * connect through the proxy. This will FAIL with the current implementation and PASS when the fix + * is applied. + * + * @throws Exception on error. + */ + @Test + public void testJdbcDriverRespectsProxySettings() throws Exception { + final int targetPort = FLIGHT_SERVER_TEST_EXTENSION.getPort(); + + String originalHttpsProxyHost = System.getProperty("https.proxyHost"); + String originalHttpsProxyPort = System.getProperty("https.proxyPort"); + String originalNonProxyHosts = System.getProperty("http.nonProxyHosts"); + + try (SimpleProxyDetector proxy = new SimpleProxyDetector()) { + proxy.start(); + + System.setProperty("https.proxyHost", "localhost"); + System.setProperty("https.proxyPort", String.valueOf(proxy.getPort())); + // Ensure localhost is not in the non-proxy hosts list + System.setProperty("http.nonProxyHosts", ""); + + final Properties properties = new Properties(); + properties.put(ArrowFlightConnectionProperty.USER.camelName(), userTest); + properties.put(ArrowFlightConnectionProperty.PASSWORD.camelName(), passTest); + properties.put("useEncryption", false); + + // Use "example.com" as the target host to trigger proxy usage + // The proxy will receive the connection attempt, proving proxy settings are respected + try (Connection connection = + DriverManager.getConnection( + "jdbc:arrow-flight-sql://example.com:" + targetPort, properties)) { + // Connection will fail, but that's OK - we just want to see if proxy was contacted + } catch (Exception e) { + // Expected - proxy doesn't forward + } + + assertTrue( + proxy.wasContacted(), + "JDBC driver should respect JVM proxy settings. " + + "The proxy did not receive a connection, indicating proxy settings are ignored."); + + } finally { + if (originalHttpsProxyHost == null) { + System.clearProperty("https.proxyHost"); + } else { + System.setProperty("https.proxyHost", originalHttpsProxyHost); + } + if (originalHttpsProxyPort == null) { + System.clearProperty("https.proxyPort"); + } else { + System.setProperty("https.proxyPort", originalHttpsProxyPort); + } + if (originalNonProxyHosts == null) { + System.clearProperty("http.nonProxyHosts"); + } else { + System.setProperty("http.nonProxyHosts", originalNonProxyHosts); + } + } + } + + /** Simple proxy detector for testing proxy support. */ + private static class SimpleProxyDetector implements AutoCloseable { + private final int port; + private final java.util.concurrent.atomic.AtomicBoolean contacted = + new java.util.concurrent.atomic.AtomicBoolean(false); + private final java.util.concurrent.CountDownLatch started = + new java.util.concurrent.CountDownLatch(1); + private Thread thread; + + SimpleProxyDetector() throws java.io.IOException { + try (java.net.ServerSocket socket = new java.net.ServerSocket(0)) { + socket.setReuseAddress(true); + this.port = socket.getLocalPort(); + } + } + + void start() throws InterruptedException { + thread = + new Thread( + () -> { + try (java.net.ServerSocket socket = new java.net.ServerSocket(port)) { + started.countDown(); + socket.setSoTimeout(5000); + socket.accept(); + contacted.set(true); + } catch (Exception e) { + // Timeout or error + } + }); + thread.setDaemon(true); + thread.start(); + started.await(5, java.util.concurrent.TimeUnit.SECONDS); + } + + int getPort() { + return port; + } + + boolean wasContacted() { + return contacted.get(); + } + + @Override + public void close() { + if (thread != null) { + thread.interrupt(); + } + } + } } From 18b30dd8821b23b45af6942b600b87afecd6ea1e Mon Sep 17 00:00:00 2001 From: Pedro Matias Date: Thu, 14 May 2026 03:43:18 +0100 Subject: [PATCH 2/6] Test using ProxySelector spy --- .../arrow/driver/jdbc/ConnectionTest.java | 128 ++++-------------- 1 file changed, 28 insertions(+), 100 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java index 3369b45f20..d9122d1015 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java @@ -26,6 +26,11 @@ import static org.junit.jupiter.api.Assertions.fail; import com.google.protobuf.Message; +import java.io.IOException; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; import java.net.URISyntaxException; import java.sql.Connection; import java.sql.Driver; @@ -33,8 +38,10 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import org.apache.arrow.driver.jdbc.authentication.UserPasswordAuthentication; import org.apache.arrow.driver.jdbc.client.ArrowFlightSqlClientHandler; @@ -769,117 +776,38 @@ public void testResultSetsFromDatabaseMetadataClosedOnConnectionClose() throws E } } - /** - * Test that JDBC driver respects JVM proxy settings. - * - *

This test verifies that when JVM proxy properties are set, the Flight client attempts to - * connect through the proxy. This will FAIL with the current implementation and PASS when the fix - * is applied. - * - * @throws Exception on error. - */ @Test - public void testJdbcDriverRespectsProxySettings() throws Exception { - final int targetPort = FLIGHT_SERVER_TEST_EXTENSION.getPort(); - - String originalHttpsProxyHost = System.getProperty("https.proxyHost"); - String originalHttpsProxyPort = System.getProperty("https.proxyPort"); - String originalNonProxyHosts = System.getProperty("http.nonProxyHosts"); - - try (SimpleProxyDetector proxy = new SimpleProxyDetector()) { - proxy.start(); + public void testJdbcDriverConsultsProxySelectorForTcpConnections() throws Exception { + AtomicBoolean consulted = new AtomicBoolean(false); + ProxySelector original = ProxySelector.getDefault(); + ProxySelector.setDefault( + new ProxySelector() { + @Override + public List select(URI uri) { + consulted.set(true); + return original.select(uri); + } - System.setProperty("https.proxyHost", "localhost"); - System.setProperty("https.proxyPort", String.valueOf(proxy.getPort())); - // Ensure localhost is not in the non-proxy hosts list - System.setProperty("http.nonProxyHosts", ""); + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException e) {} + }); + try { final Properties properties = new Properties(); properties.put(ArrowFlightConnectionProperty.USER.camelName(), userTest); properties.put(ArrowFlightConnectionProperty.PASSWORD.camelName(), passTest); properties.put("useEncryption", false); - // Use "example.com" as the target host to trigger proxy usage - // The proxy will receive the connection attempt, proving proxy settings are respected - try (Connection connection = - DriverManager.getConnection( - "jdbc:arrow-flight-sql://example.com:" + targetPort, properties)) { - // Connection will fail, but that's OK - we just want to see if proxy was contacted - } catch (Exception e) { - // Expected - proxy doesn't forward - } + DriverManager.getConnection( + "jdbc:arrow-flight-sql://localhost:" + FLIGHT_SERVER_TEST_EXTENSION.getPort(), + properties) + .close(); assertTrue( - proxy.wasContacted(), - "JDBC driver should respect JVM proxy settings. " - + "The proxy did not receive a connection, indicating proxy settings are ignored."); - + consulted.get(), + "JDBC driver must consult ProxySelector so JVM proxy settings are respected"); } finally { - if (originalHttpsProxyHost == null) { - System.clearProperty("https.proxyHost"); - } else { - System.setProperty("https.proxyHost", originalHttpsProxyHost); - } - if (originalHttpsProxyPort == null) { - System.clearProperty("https.proxyPort"); - } else { - System.setProperty("https.proxyPort", originalHttpsProxyPort); - } - if (originalNonProxyHosts == null) { - System.clearProperty("http.nonProxyHosts"); - } else { - System.setProperty("http.nonProxyHosts", originalNonProxyHosts); - } - } - } - - /** Simple proxy detector for testing proxy support. */ - private static class SimpleProxyDetector implements AutoCloseable { - private final int port; - private final java.util.concurrent.atomic.AtomicBoolean contacted = - new java.util.concurrent.atomic.AtomicBoolean(false); - private final java.util.concurrent.CountDownLatch started = - new java.util.concurrent.CountDownLatch(1); - private Thread thread; - - SimpleProxyDetector() throws java.io.IOException { - try (java.net.ServerSocket socket = new java.net.ServerSocket(0)) { - socket.setReuseAddress(true); - this.port = socket.getLocalPort(); - } - } - - void start() throws InterruptedException { - thread = - new Thread( - () -> { - try (java.net.ServerSocket socket = new java.net.ServerSocket(port)) { - started.countDown(); - socket.setSoTimeout(5000); - socket.accept(); - contacted.set(true); - } catch (Exception e) { - // Timeout or error - } - }); - thread.setDaemon(true); - thread.start(); - started.await(5, java.util.concurrent.TimeUnit.SECONDS); - } - - int getPort() { - return port; - } - - boolean wasContacted() { - return contacted.get(); - } - - @Override - public void close() { - if (thread != null) { - thread.interrupt(); - } + ProxySelector.setDefault(original); } } } From e895aa411435c704b391956e68c2bf6a3b56e7be Mon Sep 17 00:00:00 2001 From: Pedro Matias Date: Sun, 30 Aug 2026 03:13:46 +0100 Subject: [PATCH 3/6] GH-1027: Validate port range in ArrowFlightConnectionConfigImpl.getPort() Co-Authored-By: Claude Sonnet 4.6 --- .../jdbc/utils/ArrowFlightConnectionConfigImpl.java | 8 ++++++-- .../org/apache/arrow/driver/jdbc/ConnectionTest.java | 2 +- .../arrow/driver/jdbc/FlightServerTestExtension.java | 2 +- .../arrow/driver/jdbc/OAuthIntegrationTest.java | 12 ++++++------ .../utils/ArrowFlightConnectionConfigImplTest.java | 10 ++++++++-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java index d0ba74dbcc..5c1551b339 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java @@ -55,8 +55,12 @@ public String getHost() { * * @return the port. */ - public int getPort() { - return ArrowFlightConnectionProperty.PORT.getInteger(properties); + public int getPort() throws SQLException { + final int port = ArrowFlightConnectionProperty.PORT.getInteger(properties); + if (port < 1 || port > 65535) { + throw new SQLException("Invalid port " + port + ": must be between 1 and 65535."); + } + return port; } /** diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java index d9122d1015..957cb02282 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java @@ -130,7 +130,7 @@ public void testUnencryptedConnectionShouldOpenSuccessfullyWhenProvidedValidCred * connection should fail if a token is passed in. */ @Test - public void testTokenOverridesUsernameAndPasswordAuth() { + public void testTokenOverridesUsernameAndPasswordAuth() throws Exception { final Properties properties = new Properties(); properties.put(ArrowFlightConnectionProperty.HOST.camelName(), "localhost"); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java index f71114e1b5..72a02ae3ae 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java @@ -211,7 +211,7 @@ private FlightServer getStartServer( * * @return the port value. */ - public int getPort() { + public int getPort() throws SQLException { return config.getPort(); } diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java index 5e782db031..aeee65179b 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java @@ -161,7 +161,7 @@ private void enqueueErrorResponse(String error, String description) { .build()); } - private Properties createBaseProperties() { + private Properties createBaseProperties() throws SQLException { Properties props = new Properties(); props.put(ArrowFlightConnectionProperty.HOST.camelName(), "localhost"); props.put( @@ -170,7 +170,7 @@ private Properties createBaseProperties() { return props; } - private String getJdbcUrl() { + private String getJdbcUrl() throws SQLException { return String.format( "jdbc:arrow-flight-sql://localhost:%d", FLIGHT_SERVER_TEST_EXTENSION.getPort()); } @@ -408,7 +408,7 @@ public void testTokenRefreshAfterExpiration() throws Exception { // ==================== Error Handling Tests ==================== @Test - public void testMissingRequiredParametersClientCredentials() { + public void testMissingRequiredParametersClientCredentials() throws Exception { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "client_credentials"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), tokenEndpoint.toString()); @@ -418,7 +418,7 @@ public void testMissingRequiredParametersClientCredentials() { } @Test - public void testMissingRequiredParametersTokenExchange() { + public void testMissingRequiredParametersTokenExchange() throws Exception { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "token_exchange"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), tokenEndpoint.toString()); @@ -428,7 +428,7 @@ public void testMissingRequiredParametersTokenExchange() { } @Test - public void testInvalidOAuthFlow() { + public void testInvalidOAuthFlow() throws Exception { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "invalid_flow"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), tokenEndpoint.toString()); @@ -437,7 +437,7 @@ public void testInvalidOAuthFlow() { } @Test - public void testMalformedTokenEndpoint() { + public void testMalformedTokenEndpoint() throws Exception { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "client_credentials"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), "not-a-valid-uri://"); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java index ecce7708c0..22cf8bbc87 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java @@ -72,7 +72,7 @@ public void testGetProperty( } public static Stream provideParameters() { - int port = RANDOM.nextInt(Short.toUnsignedInt(Short.MAX_VALUE)); + int port = RANDOM.nextInt(65535) + 1; boolean useEncryption = RANDOM.nextBoolean(); int threadPoolSize = RANDOM.nextInt(getRuntime().availableProcessors()); return Stream.of( @@ -87,7 +87,13 @@ public static Stream provideParameters() { port, port, (Function) - ArrowFlightConnectionConfigImpl::getPort), + config -> { + try { + return config.getPort(); + } catch (java.sql.SQLException e) { + throw new RuntimeException(e); + } + }), Arguments.of( USER, "user", From 084606a22cb5cd0b0a651a2edb6abe8dd0db7b4a Mon Sep 17 00:00:00 2001 From: Pedro Matias Date: Sun, 30 Aug 2026 03:48:13 +0100 Subject: [PATCH 4/6] GH-1027: Move port validation to NettyClientBuilder.build() Validate the port synchronously in NettyClientBuilder.build() before calling forAddress(String, int), restoring the fail-fast behaviour that was lost when switching away from forAddress(SocketAddress). Placing the check here protects all callers (not just JDBC), and the resulting IllegalArgumentException is already caught and wrapped as SQLException by ArrowFlightSqlClientHandler.Builder.build(). Reverts the validation that was previously added to ArrowFlightConnectionConfigImpl.getPort() and the associated throws-SQLException ripple across FlightServerTestExtension, OAuthIntegrationTest, and ArrowFlightConnectionConfigImplTest. Co-Authored-By: Claude Sonnet 4.6 --- .../apache/arrow/flight/grpc/NettyClientBuilder.java | 9 ++++++--- .../jdbc/utils/ArrowFlightConnectionConfigImpl.java | 8 ++------ .../arrow/driver/jdbc/FlightServerTestExtension.java | 2 +- .../arrow/driver/jdbc/OAuthIntegrationTest.java | 12 ++++++------ .../utils/ArrowFlightConnectionConfigImplTest.java | 10 ++-------- 5 files changed, 17 insertions(+), 24 deletions(-) diff --git a/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java b/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java index 65ecb51ad8..e32a446971 100644 --- a/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java +++ b/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java @@ -139,9 +139,12 @@ public NettyChannelBuilder build() { case LocationSchemes.GRPC_INSECURE: case LocationSchemes.GRPC_TLS: { - builder = - NettyChannelBuilder.forAddress( - location.getUri().getHost(), location.getUri().getPort()); + final int port = location.getUri().getPort(); + if (port < 1 || port > 65535) { + throw new IllegalArgumentException( + "Invalid port " + port + ": must be between 1 and 65535."); + } + builder = NettyChannelBuilder.forAddress(location.getUri().getHost(), port); break; } case LocationSchemes.GRPC_DOMAIN_SOCKET: diff --git a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java index 5c1551b339..d0ba74dbcc 100644 --- a/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java +++ b/flight/flight-sql-jdbc-core/src/main/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImpl.java @@ -55,12 +55,8 @@ public String getHost() { * * @return the port. */ - public int getPort() throws SQLException { - final int port = ArrowFlightConnectionProperty.PORT.getInteger(properties); - if (port < 1 || port > 65535) { - throw new SQLException("Invalid port " + port + ": must be between 1 and 65535."); - } - return port; + public int getPort() { + return ArrowFlightConnectionProperty.PORT.getInteger(properties); } /** diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java index 72a02ae3ae..f71114e1b5 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/FlightServerTestExtension.java @@ -211,7 +211,7 @@ private FlightServer getStartServer( * * @return the port value. */ - public int getPort() throws SQLException { + public int getPort() { return config.getPort(); } diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java index aeee65179b..5e782db031 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/OAuthIntegrationTest.java @@ -161,7 +161,7 @@ private void enqueueErrorResponse(String error, String description) { .build()); } - private Properties createBaseProperties() throws SQLException { + private Properties createBaseProperties() { Properties props = new Properties(); props.put(ArrowFlightConnectionProperty.HOST.camelName(), "localhost"); props.put( @@ -170,7 +170,7 @@ private Properties createBaseProperties() throws SQLException { return props; } - private String getJdbcUrl() throws SQLException { + private String getJdbcUrl() { return String.format( "jdbc:arrow-flight-sql://localhost:%d", FLIGHT_SERVER_TEST_EXTENSION.getPort()); } @@ -408,7 +408,7 @@ public void testTokenRefreshAfterExpiration() throws Exception { // ==================== Error Handling Tests ==================== @Test - public void testMissingRequiredParametersClientCredentials() throws Exception { + public void testMissingRequiredParametersClientCredentials() { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "client_credentials"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), tokenEndpoint.toString()); @@ -418,7 +418,7 @@ public void testMissingRequiredParametersClientCredentials() throws Exception { } @Test - public void testMissingRequiredParametersTokenExchange() throws Exception { + public void testMissingRequiredParametersTokenExchange() { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "token_exchange"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), tokenEndpoint.toString()); @@ -428,7 +428,7 @@ public void testMissingRequiredParametersTokenExchange() throws Exception { } @Test - public void testInvalidOAuthFlow() throws Exception { + public void testInvalidOAuthFlow() { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "invalid_flow"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), tokenEndpoint.toString()); @@ -437,7 +437,7 @@ public void testInvalidOAuthFlow() throws Exception { } @Test - public void testMalformedTokenEndpoint() throws Exception { + public void testMalformedTokenEndpoint() { Properties props = createBaseProperties(); props.put(ArrowFlightConnectionProperty.OAUTH_FLOW.camelName(), "client_credentials"); props.put(ArrowFlightConnectionProperty.OAUTH_TOKEN_URI.camelName(), "not-a-valid-uri://"); diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java index 22cf8bbc87..ecce7708c0 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/utils/ArrowFlightConnectionConfigImplTest.java @@ -72,7 +72,7 @@ public void testGetProperty( } public static Stream provideParameters() { - int port = RANDOM.nextInt(65535) + 1; + int port = RANDOM.nextInt(Short.toUnsignedInt(Short.MAX_VALUE)); boolean useEncryption = RANDOM.nextBoolean(); int threadPoolSize = RANDOM.nextInt(getRuntime().availableProcessors()); return Stream.of( @@ -87,13 +87,7 @@ public static Stream provideParameters() { port, port, (Function) - config -> { - try { - return config.getPort(); - } catch (java.sql.SQLException e) { - throw new RuntimeException(e); - } - }), + ArrowFlightConnectionConfigImpl::getPort), Arguments.of( USER, "user", From 2cc7a101795ec85cbdc61fce6b72308433a9d2f8 Mon Sep 17 00:00:00 2001 From: Pedro Matias Date: Sun, 30 Aug 2026 03:51:37 +0100 Subject: [PATCH 5/6] GH-1027: Revert throws Exception from testTokenOverridesUsernameAndPasswordAuth Missed in the previous cleanup commit; this was a ripple from the now- removed throws-SQLException on ArrowFlightConnectionConfigImpl.getPort(). Co-Authored-By: Claude Sonnet 4.6 --- .../test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java index 957cb02282..d9122d1015 100644 --- a/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java +++ b/flight/flight-sql-jdbc-core/src/test/java/org/apache/arrow/driver/jdbc/ConnectionTest.java @@ -130,7 +130,7 @@ public void testUnencryptedConnectionShouldOpenSuccessfullyWhenProvidedValidCred * connection should fail if a token is passed in. */ @Test - public void testTokenOverridesUsernameAndPasswordAuth() throws Exception { + public void testTokenOverridesUsernameAndPasswordAuth() { final Properties properties = new Properties(); properties.put(ArrowFlightConnectionProperty.HOST.camelName(), "localhost"); From dc80adc75c7d7461c2a883ffd6600d074c3d7593 Mon Sep 17 00:00:00 2001 From: Pedro Matias Date: Sun, 30 Aug 2026 03:59:31 +0100 Subject: [PATCH 6/6] GH-1027: Allow port 0 through NettyClientBuilder validation Port 0 is used in several existing tests as a placeholder. It does not cause the async-hang issue this validation was introduced to prevent (that affects truly out-of-range values). Tightening the lower bound to 1 and fixing those tests is left for a follow-up PR. Co-Authored-By: Claude Sonnet 4.6 --- .../java/org/apache/arrow/flight/grpc/NettyClientBuilder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java b/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java index e32a446971..7df1a0a2a2 100644 --- a/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java +++ b/flight/flight-core/src/main/java/org/apache/arrow/flight/grpc/NettyClientBuilder.java @@ -140,9 +140,9 @@ public NettyChannelBuilder build() { case LocationSchemes.GRPC_TLS: { final int port = location.getUri().getPort(); - if (port < 1 || port > 65535) { + if (port < 0 || port > 65535) { throw new IllegalArgumentException( - "Invalid port " + port + ": must be between 1 and 65535."); + "Invalid port " + port + ": must be between 0 and 65535."); } builder = NettyChannelBuilder.forAddress(location.getUri().getHost(), port); break;