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-12414-4cf17541df318472b5fffdfcbaab2b1a33ec31c8
in repository https://gitbox.apache.org/repos/asf/seatunnel.git

commit ea5f089674ea782c9399503258a0940459cf7abb
Author: TianHengZhuang <[email protected]>
AuthorDate: Tue Sep 29 13:35:17 2026 +0000

    [Improve][Connector-V2][Easysearch] Declarative optionRule value 
constraints for source and sink (#12414)
---
 .../easysearch/sink/EasysearchSinkFactory.java     |  16 ++-
 .../easysearch/source/EasysearchSourceFactory.java |  12 +-
 .../easysearch/EasysearchFactoryTest.java          | 122 ++++++++++++++++++++-
 3 files changed, 143 insertions(+), 7 deletions(-)

diff --git 
a/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/sink/EasysearchSinkFactory.java
 
b/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/sink/EasysearchSinkFactory.java
index 5ab636605e..ec38d23166 100644
--- 
a/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/sink/EasysearchSinkFactory.java
+++ 
b/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/sink/EasysearchSinkFactory.java
@@ -17,6 +17,7 @@
 
 package org.apache.seatunnel.connectors.seatunnel.easysearch.sink;
 
+import org.apache.seatunnel.api.configuration.util.Conditions;
 import org.apache.seatunnel.api.configuration.util.OptionRule;
 import org.apache.seatunnel.api.table.connector.TableSink;
 import org.apache.seatunnel.api.table.factory.Factory;
@@ -36,14 +37,23 @@ public class EasysearchSinkFactory implements 
TableSinkFactory {
     @Override
     public OptionRule optionRule() {
         return OptionRule.builder()
-                .required(EasysearchSinkOptions.HOSTS, 
EasysearchSinkOptions.INDEX)
+                .required(
+                        EasysearchSinkOptions.HOSTS,
+                        Conditions.notEmpty(EasysearchSinkOptions.HOSTS))
+                .required(
+                        EasysearchSinkOptions.INDEX,
+                        Conditions.notBlank(EasysearchSinkOptions.INDEX))
+                .optional(
+                        EasysearchSinkOptions.MAX_BATCH_SIZE,
+                        
Conditions.greaterThan(EasysearchSinkOptions.MAX_BATCH_SIZE, 0))
+                .optional(
+                        EasysearchSinkOptions.MAX_RETRY_COUNT,
+                        
Conditions.greaterOrEqual(EasysearchSinkOptions.MAX_RETRY_COUNT, 0))
                 .optional(
                         EasysearchSinkOptions.USERNAME,
                         EasysearchSinkOptions.PASSWORD,
                         EasysearchSinkOptions.PRIMARY_KEYS,
                         EasysearchSinkOptions.KEY_DELIMITER,
-                        EasysearchSinkOptions.MAX_RETRY_COUNT,
-                        EasysearchSinkOptions.MAX_BATCH_SIZE,
                         EasysearchSinkOptions.TLS_VERIFY_CERTIFICATE,
                         EasysearchSinkOptions.TLS_VERIFY_HOSTNAME,
                         EasysearchSinkOptions.TLS_KEY_STORE_PATH,
diff --git 
a/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/source/EasysearchSourceFactory.java
 
b/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/source/EasysearchSourceFactory.java
index e766db2640..38a0cb9326 100644
--- 
a/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/source/EasysearchSourceFactory.java
+++ 
b/seatunnel-connectors-v2/connector-easysearch/src/main/java/org/apache/seatunnel/connectors/seatunnel/easysearch/source/EasysearchSourceFactory.java
@@ -20,6 +20,7 @@ package 
org.apache.seatunnel.connectors.seatunnel.easysearch.source;
 import org.apache.seatunnel.shade.com.google.common.collect.Lists;
 
 import org.apache.seatunnel.api.configuration.ReadonlyConfig;
+import org.apache.seatunnel.api.configuration.util.Conditions;
 import org.apache.seatunnel.api.configuration.util.OptionRule;
 import org.apache.seatunnel.api.options.ConnectorCommonOptions;
 import org.apache.seatunnel.api.source.SeaTunnelSource;
@@ -59,12 +60,19 @@ public class EasysearchSourceFactory implements 
TableSourceFactory {
     @Override
     public OptionRule optionRule() {
         return OptionRule.builder()
-                .required(EasysearchSourceOptions.HOSTS, 
EasysearchSourceOptions.INDEX)
+                .required(
+                        EasysearchSourceOptions.HOSTS,
+                        Conditions.notEmpty(EasysearchSourceOptions.HOSTS))
+                .required(
+                        EasysearchSourceOptions.INDEX,
+                        Conditions.notBlank(EasysearchSourceOptions.INDEX))
+                .optional(
+                        EasysearchSourceOptions.SCROLL_SIZE,
+                        
Conditions.greaterThan(EasysearchSourceOptions.SCROLL_SIZE, 0))
                 .optional(
                         EasysearchSourceOptions.USERNAME,
                         EasysearchSourceOptions.PASSWORD,
                         EasysearchSourceOptions.SCROLL_TIME,
-                        EasysearchSourceOptions.SCROLL_SIZE,
                         EasysearchSourceOptions.QUERY,
                         EasysearchSourceOptions.TLS_VERIFY_CERTIFICATE,
                         EasysearchSourceOptions.TLS_VERIFY_HOSTNAME,
diff --git 
a/seatunnel-connectors-v2/connector-easysearch/src/test/java/org/apache/seatunnel/connectors/seatunnel/easysearch/EasysearchFactoryTest.java
 
b/seatunnel-connectors-v2/connector-easysearch/src/test/java/org/apache/seatunnel/connectors/seatunnel/easysearch/EasysearchFactoryTest.java
index 6da684a5d0..c0920510ec 100644
--- 
a/seatunnel-connectors-v2/connector-easysearch/src/test/java/org/apache/seatunnel/connectors/seatunnel/easysearch/EasysearchFactoryTest.java
+++ 
b/seatunnel-connectors-v2/connector-easysearch/src/test/java/org/apache/seatunnel/connectors/seatunnel/easysearch/EasysearchFactoryTest.java
@@ -17,17 +17,135 @@
 
 package org.apache.seatunnel.connectors.seatunnel.easysearch;
 
+import org.apache.seatunnel.api.configuration.ReadonlyConfig;
+import org.apache.seatunnel.api.configuration.util.ConfigValidator;
+import org.apache.seatunnel.api.configuration.util.OptionValidationException;
 import 
org.apache.seatunnel.connectors.seatunnel.easysearch.sink.EasysearchSinkFactory;
 import 
org.apache.seatunnel.connectors.seatunnel.easysearch.source.EasysearchSourceFactory;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
 public class EasysearchFactoryTest {
 
+    private final EasysearchSourceFactory sourceFactory = new 
EasysearchSourceFactory();
+    private final EasysearchSinkFactory sinkFactory = new 
EasysearchSinkFactory();
+
+    private static Map<String, Object> validSourceConfig() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("hosts", Collections.singletonList("http://127.0.0.1:9200";));
+        map.put("index", "demo");
+        map.put("source", Collections.singletonList("id"));
+        return map;
+    }
+
+    private static Map<String, Object> validSinkConfig() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("hosts", Collections.singletonList("http://127.0.0.1:9200";));
+        map.put("index", "demo");
+        return map;
+    }
+
+    private void validateSource(Map<String, Object> map) {
+        
ConfigValidator.of(ReadonlyConfig.fromMap(map)).validate(sourceFactory.optionRule());
+    }
+
+    private void validateSink(Map<String, Object> map) {
+        
ConfigValidator.of(ReadonlyConfig.fromMap(map)).validate(sinkFactory.optionRule());
+    }
+
     @Test
     void optionRule() {
-        Assertions.assertNotNull((new EasysearchSourceFactory()).optionRule());
-        Assertions.assertNotNull((new EasysearchSinkFactory()).optionRule());
+        Assertions.assertNotNull(sourceFactory.optionRule());
+        Assertions.assertNotNull(sinkFactory.optionRule());
+    }
+
+    @Test
+    void validSourceConfigPassesValidation() {
+        validateSource(validSourceConfig());
+    }
+
+    @Test
+    void validSinkConfigPassesValidation() {
+        validateSink(validSinkConfig());
+    }
+
+    @Test
+    void validNumericBoundsPassValidation() {
+        Map<String, Object> source = validSourceConfig();
+        source.put("scroll_size", 1);
+        validateSource(source);
+
+        Map<String, Object> sink = validSinkConfig();
+        sink.put("max_batch_size", 1);
+        sink.put("max_retry_count", 0);
+        validateSink(sink);
+    }
+
+    @Test
+    void blankIndexIsRejectedForSourceAndSink() {
+        Map<String, Object> source = validSourceConfig();
+        source.put("index", "  ");
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSource(source));
+
+        Map<String, Object> sink = validSinkConfig();
+        sink.put("index", "");
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSink(sink));
+    }
+
+    @Test
+    void emptyHostsIsRejectedForSourceAndSink() {
+        Map<String, Object> source = validSourceConfig();
+        source.put("hosts", Collections.emptyList());
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSource(source));
+
+        Map<String, Object> sink = validSinkConfig();
+        sink.put("hosts", Collections.emptyList());
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSink(sink));
+    }
+
+    @Test
+    void missingHostsOrIndexIsRejected() {
+        Map<String, Object> source = validSourceConfig();
+        source.remove("hosts");
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSource(source));
+
+        Map<String, Object> sink = validSinkConfig();
+        sink.remove("index");
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSink(sink));
+    }
+
+    @Test
+    void nonPositiveScrollSizeIsRejected() {
+        Map<String, Object> source = validSourceConfig();
+        source.put("scroll_size", 0);
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSource(source));
+    }
+
+    @Test
+    void nonPositiveMaxBatchSizeIsRejected() {
+        Map<String, Object> sink = validSinkConfig();
+        sink.put("max_batch_size", 0);
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSink(sink));
+    }
+
+    @Test
+    void negativeMaxRetryCountIsRejected() {
+        Map<String, Object> sink = validSinkConfig();
+        sink.put("max_retry_count", -1);
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSink(sink));
+    }
+
+    @Test
+    void exclusiveSourceAndSchemaRejected() {
+        Map<String, Object> map = validSourceConfig();
+        Map<String, Object> schema = new HashMap<>();
+        schema.put("fields", new HashMap<String, Object>());
+        map.put("schema", schema);
+        Assertions.assertThrows(OptionValidationException.class, () -> 
validateSource(map));
     }
 }

Reply via email to