This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] 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 98182ca59c [Improve][Connector-V2] Migrate HugeGraph sink validation
to OptionRule (#12075)
98182ca59c is described below
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;
+ }
}