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

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/dev/pr-12075-1e450e11f7c8e3ef78d186b0a407148d5faed939
in repository https://gitbox.apache.org/repos/asf/seatunnel.git

commit 98182ca59c93c10390717af4a49b8806f5c555f1
Author: Nikhil kumar <[email protected]>
AuthorDate: Fri Sep 4 03:50:30 2026 +0000

    [Improve][Connector-V2] Migrate HugeGraph sink validation to OptionRule 
(#12075)
---
 .../hugegraph/sink/HugeGraphSinkFactory.java       | 25 ++++--
 .../hugegraph/sink/HugeGraphSinkFactoryTest.java   | 95 +++++++++++++++++++++-
 2 files changed, 114 insertions(+), 6 deletions(-)

diff --git 
a/seatunnel-connectors-v2/connector-hugegraph/src/main/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactory.java
 
b/seatunnel-connectors-v2/connector-hugegraph/src/main/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactory.java
index fa4630a558..25140b8507 100644
--- 
a/seatunnel-connectors-v2/connector-hugegraph/src/main/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactory.java
+++ 
b/seatunnel-connectors-v2/connector-hugegraph/src/main/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactory.java
@@ -29,6 +29,11 @@ import 
org.apache.seatunnel.connectors.seatunnel.hugegraph.config.HugeGraphSinkO
 
 import com.google.auto.service.AutoService;
 
+import static 
org.apache.seatunnel.api.configuration.util.Conditions.greaterOrEqual;
+import static 
org.apache.seatunnel.api.configuration.util.Conditions.lessOrEqual;
+import static org.apache.seatunnel.api.configuration.util.Conditions.matches;
+import static org.apache.seatunnel.api.configuration.util.Conditions.notBlank;
+
 @AutoService(Factory.class)
 public class HugeGraphSinkFactory implements TableSinkFactory {
 
@@ -47,11 +52,16 @@ public class HugeGraphSinkFactory implements 
TableSinkFactory {
     public OptionRule optionRule() {
         return OptionRule.builder()
                 // connection config
-                .required(HugeGraphOptions.HOST, HugeGraphOptions.PORT, 
HugeGraphOptions.GRAPH_NAME)
+                .required(HugeGraphOptions.HOST, 
notBlank(HugeGraphOptions.HOST))
+                .required(
+                        HugeGraphOptions.PORT,
+                        greaterOrEqual(HugeGraphOptions.PORT, 1),
+                        lessOrEqual(HugeGraphOptions.PORT, 65535))
+                .required(HugeGraphOptions.GRAPH_NAME, 
notBlank(HugeGraphOptions.GRAPH_NAME))
+                .bundled(HugeGraphOptions.USERNAME, HugeGraphOptions.PASSWORD)
+                .optional(
+                        HugeGraphOptions.PROTOCOL, 
matches(HugeGraphOptions.PROTOCOL, "(?i)https?"))
                 .optional(
-                        HugeGraphOptions.PROTOCOL,
-                        HugeGraphOptions.USERNAME,
-                        HugeGraphOptions.PASSWORD,
                         // Optional connection setting passed through to 
select the HugeGraph graph
                         // space (defaults to "DEFAULT").
                         HugeGraphOptions.GRAPH_SPACE)
@@ -79,8 +89,13 @@ public class HugeGraphSinkFactory implements 
TableSinkFactory {
                 // retry config
                 .optional(
                         HugeGraphOptions.MAX_RETRIES,
+                        greaterOrEqual(HugeGraphOptions.MAX_RETRIES, 0))
+                .optional(
                         HugeGraphOptions.RETRY_BACKOFF_MS,
-                        HugeGraphOptions.RETRY_BACKOFF_MAX_MS)
+                        greaterOrEqual(HugeGraphOptions.RETRY_BACKOFF_MS, 0))
+                .optional(
+                        HugeGraphOptions.RETRY_BACKOFF_MAX_MS,
+                        greaterOrEqual(HugeGraphOptions.RETRY_BACKOFF_MAX_MS, 
0))
                 // deprecated field selection
                 .optional(HugeGraphSinkOptions.SELECTED_FIELDS, 
HugeGraphSinkOptions.IGNORED_FIELDS)
                 .build();
diff --git 
a/seatunnel-connectors-v2/connector-hugegraph/src/test/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactoryTest.java
 
b/seatunnel-connectors-v2/connector-hugegraph/src/test/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactoryTest.java
index b8db1995eb..4f5700ecc9 100644
--- 
a/seatunnel-connectors-v2/connector-hugegraph/src/test/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactoryTest.java
+++ 
b/seatunnel-connectors-v2/connector-hugegraph/src/test/java/org/apache/seatunnel/connectors/seatunnel/hugegraph/sink/HugeGraphSinkFactoryTest.java
@@ -18,17 +18,27 @@
 package org.apache.seatunnel.connectors.seatunnel.hugegraph.sink;
 
 import org.apache.seatunnel.api.configuration.Option;
+import org.apache.seatunnel.api.configuration.ReadonlyConfig;
+import org.apache.seatunnel.api.configuration.util.ConfigValidator;
+import org.apache.seatunnel.api.configuration.util.OptionRule;
+import org.apache.seatunnel.api.configuration.util.OptionValidationException;
 import 
org.apache.seatunnel.connectors.seatunnel.hugegraph.config.HugeGraphOptions;
 import 
org.apache.seatunnel.connectors.seatunnel.hugegraph.config.HugeGraphSinkOptions;
 
 import org.junit.jupiter.api.Test;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 class HugeGraphSinkFactoryTest {
 
+    private final OptionRule optionRule = new 
HugeGraphSinkFactory().optionRule();
+
     /**
      * Every option the sink actually reads must be declared in {@code 
optionRule()}; otherwise
      * {@code seatunnel.sh --config x --check} (and STATIC dry-run) reject it 
as an unknown key and
@@ -36,7 +46,7 @@ class HugeGraphSinkFactoryTest {
      */
     @Test
     void optionRuleDeclaresAllReadOptions() {
-        List<Option<?>> optional = new 
HugeGraphSinkFactory().optionRule().getOptionalOptions();
+        List<Option<?>> optional = optionRule.getOptionalOptions();
         assertTrue(
                 optional.contains(HugeGraphSinkOptions.DATA_SAVE_MODE), 
"data_save_mode missing");
         assertTrue(optional.contains(HugeGraphOptions.CHECK_VERTEX), 
"check_vertex missing");
@@ -51,4 +61,87 @@ class HugeGraphSinkFactoryTest {
                 optional.contains(HugeGraphOptions.RETRY_BACKOFF_MAX_MS),
                 "retry_backoff_max_ms missing");
     }
+
+    @Test
+    void acceptsValidConnectionOptions() {
+        assertDoesNotThrow(() -> validate(requiredConfig()));
+
+        Map<String, Object> config = requiredConfig();
+        config.put(HugeGraphOptions.PROTOCOL.key(), "HTTPS");
+        config.put(HugeGraphOptions.USERNAME.key(), "user");
+        config.put(HugeGraphOptions.PASSWORD.key(), "password");
+        config.put(HugeGraphOptions.MAX_RETRIES.key(), 0);
+        config.put(HugeGraphOptions.RETRY_BACKOFF_MS.key(), 0);
+        config.put(HugeGraphOptions.RETRY_BACKOFF_MAX_MS.key(), 0);
+
+        assertDoesNotThrow(() -> validate(config));
+    }
+
+    @Test
+    void rejectsBlankRequiredConnectionOptions() {
+        Map<String, Object> blankHost = requiredConfig();
+        blankHost.put(HugeGraphOptions.HOST.key(), " ");
+        assertThrows(OptionValidationException.class, () -> 
validate(blankHost));
+
+        Map<String, Object> blankGraphName = requiredConfig();
+        blankGraphName.put(HugeGraphOptions.GRAPH_NAME.key(), "\t");
+        assertThrows(OptionValidationException.class, () -> 
validate(blankGraphName));
+    }
+
+    @Test
+    void rejectsPortOutsideValidRange() {
+        Map<String, Object> portTooLow = requiredConfig();
+        portTooLow.put(HugeGraphOptions.PORT.key(), 0);
+        assertThrows(OptionValidationException.class, () -> 
validate(portTooLow));
+
+        Map<String, Object> portTooHigh = requiredConfig();
+        portTooHigh.put(HugeGraphOptions.PORT.key(), 65536);
+        assertThrows(OptionValidationException.class, () -> 
validate(portTooHigh));
+    }
+
+    @Test
+    void rejectsUnsupportedProtocol() {
+        Map<String, Object> config = requiredConfig();
+        config.put(HugeGraphOptions.PROTOCOL.key(), "ftp");
+
+        assertThrows(OptionValidationException.class, () -> validate(config));
+    }
+
+    @Test
+    void requiresCredentialsToBeConfiguredTogether() {
+        Map<String, Object> usernameOnly = requiredConfig();
+        usernameOnly.put(HugeGraphOptions.USERNAME.key(), "user");
+        assertThrows(OptionValidationException.class, () -> 
validate(usernameOnly));
+
+        Map<String, Object> passwordOnly = requiredConfig();
+        passwordOnly.put(HugeGraphOptions.PASSWORD.key(), "password");
+        assertThrows(OptionValidationException.class, () -> 
validate(passwordOnly));
+    }
+
+    @Test
+    void rejectsNegativeRetryOptions() {
+        assertNegativeOptionRejected(HugeGraphOptions.MAX_RETRIES);
+        assertNegativeOptionRejected(HugeGraphOptions.RETRY_BACKOFF_MS);
+        assertNegativeOptionRejected(HugeGraphOptions.RETRY_BACKOFF_MAX_MS);
+    }
+
+    private void assertNegativeOptionRejected(Option<Integer> option) {
+        Map<String, Object> config = requiredConfig();
+        config.put(option.key(), -1);
+        assertThrows(OptionValidationException.class, () -> validate(config));
+    }
+
+    private void validate(Map<String, Object> config) {
+        ReadonlyConfig readonlyConfig = ReadonlyConfig.fromMap(config);
+        ConfigValidator.validateUnknownKeys(readonlyConfig, optionRule, 
"HugeGraphSink");
+        ConfigValidator.of(readonlyConfig).validate(optionRule);
+    }
+
+    private static Map<String, Object> requiredConfig() {
+        Map<String, Object> config = new HashMap<>();
+        config.put(HugeGraphOptions.HOST.key(), "127.0.0.1");
+        config.put(HugeGraphOptions.PORT.key(), 8080);
+        config.put(HugeGraphOptions.GRAPH_NAME.key(), "hugegraph");
+        return config;
+    }
 }

Reply via email to