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-12690-4ae4fee30165e9f082f80b05ec5a8f3bb810b474 in repository https://gitbox.apache.org/repos/asf/seatunnel.git
commit b3898b62d79db47d4b213c830da8745edd8fc678 Author: Supidan <[email protected]> AuthorDate: Mon Oct 12 12:02:54 2026 +0000 [Improve][Connector-V2] Validate nonblank MaxCompute source endpoint (#12690) Co-authored-by: Supidan <[email protected]> --- docs/en/connectors/source/Maxcompute.md | 2 +- docs/zh/connectors/source/Maxcompute.md | 2 +- .../maxcompute/source/MaxcomputeSourceFactory.java | 5 +- .../maxcompute/MaxcomputeSourceFactoryTest.java | 58 ++++++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/docs/en/connectors/source/Maxcompute.md b/docs/en/connectors/source/Maxcompute.md index 472f602366..b50b10b3f5 100644 --- a/docs/en/connectors/source/Maxcompute.md +++ b/docs/en/connectors/source/Maxcompute.md @@ -68,7 +68,7 @@ for parallel reads. ### endpoint [string] -`endpoint` Your Maxcompute endpoint start with http. +Your MaxCompute endpoint, starting with `http`. This option is required and must not be an empty string or contain only whitespace. Blank values are rejected during configuration validation, before connecting to MaxCompute. ### project [string] diff --git a/docs/zh/connectors/source/Maxcompute.md b/docs/zh/connectors/source/Maxcompute.md index 1336f50b42..1529983e02 100644 --- a/docs/zh/connectors/source/Maxcompute.md +++ b/docs/zh/connectors/source/Maxcompute.md @@ -65,7 +65,7 @@ import ChangeLog from '../changelog/connector-maxcompute.md'; ### endpoint [string] -`endpoint` 您的 Maxcompute 端点,以 http 开头。 +您的 MaxCompute 端点,以 `http` 开头。此选项必填,不能是空字符串或仅包含空白字符。空白值会在配置校验阶段被拒绝,不会进入 MaxCompute 连接阶段。 ### project [string] diff --git a/seatunnel-connectors-v2/connector-maxcompute/src/main/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/source/MaxcomputeSourceFactory.java b/seatunnel-connectors-v2/connector-maxcompute/src/main/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/source/MaxcomputeSourceFactory.java index 8859a9b42f..a682d607ee 100644 --- a/seatunnel-connectors-v2/connector-maxcompute/src/main/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/source/MaxcomputeSourceFactory.java +++ b/seatunnel-connectors-v2/connector-maxcompute/src/main/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/source/MaxcomputeSourceFactory.java @@ -17,6 +17,7 @@ package org.apache.seatunnel.connectors.seatunnel.maxcompute.source; +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.options.table.CatalogOptions; @@ -42,7 +43,9 @@ public class MaxcomputeSourceFactory implements TableSourceFactory { @Override public OptionRule optionRule() { return OptionRule.builder() - .required(MaxcomputeSourceOptions.ENDPOINT) + .required( + MaxcomputeSourceOptions.ENDPOINT, + Conditions.notBlank(MaxcomputeSourceOptions.ENDPOINT)) .optional( MaxcomputeSourceOptions.ACCESS_ID, MaxcomputeSourceOptions.ACCESS_KEY, diff --git a/seatunnel-connectors-v2/connector-maxcompute/src/test/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/MaxcomputeSourceFactoryTest.java b/seatunnel-connectors-v2/connector-maxcompute/src/test/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/MaxcomputeSourceFactoryTest.java index ec0c5ea932..da7474c2fb 100644 --- a/seatunnel-connectors-v2/connector-maxcompute/src/test/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/MaxcomputeSourceFactoryTest.java +++ b/seatunnel-connectors-v2/connector-maxcompute/src/test/java/org/apache/seatunnel/connectors/seatunnel/maxcompute/MaxcomputeSourceFactoryTest.java @@ -18,17 +18,75 @@ package org.apache.seatunnel.connectors.seatunnel.maxcompute; 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.maxcompute.config.MaxcomputeSourceOptions; import org.apache.seatunnel.connectors.seatunnel.maxcompute.sink.MaxcomputeSinkFactory; import org.apache.seatunnel.connectors.seatunnel.maxcompute.source.MaxcomputeSourceFactory; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; public class MaxcomputeSourceFactoryTest { + @ParameterizedTest + @ValueSource( + strings = { + "http://service.odps.aliyun.com/api", + " \thttp://service.odps.aliyun.com/api\r\n " + }) + void acceptsNonblankEndpointWithoutTrimming(String endpoint) { + Map<String, Object> config = sourceConfig(); + config.put(MaxcomputeSourceOptions.ENDPOINT.key(), endpoint); + ReadonlyConfig readonlyConfig = ReadonlyConfig.fromMap(config); + + Assertions.assertDoesNotThrow( + () -> + ConfigValidator.of(readonlyConfig) + .validate(new MaxcomputeSourceFactory().optionRule())); + Assertions.assertEquals(endpoint, readonlyConfig.get(MaxcomputeSourceOptions.ENDPOINT)); + } + + @Test + void rejectsMissingEndpoint() { + Map<String, Object> config = sourceConfig(); + config.remove(MaxcomputeSourceOptions.ENDPOINT.key()); + assertInvalidEndpoint(config); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "\t", "\n", "\r", " \t\r\n "}) + void rejectsBlankEndpoint(String endpoint) { + Map<String, Object> config = sourceConfig(); + config.put(MaxcomputeSourceOptions.ENDPOINT.key(), endpoint); + assertInvalidEndpoint(config); + } + + private Map<String, Object> sourceConfig() { + Map<String, Object> config = new HashMap<>(); + config.put(MaxcomputeSourceOptions.ENDPOINT.key(), "http://service.odps.aliyun.com/api"); + config.put(MaxcomputeSourceOptions.TABLE_NAME.key(), "test_table"); + return config; + } + + private void assertInvalidEndpoint(Map<String, Object> config) { + OptionValidationException error = + Assertions.assertThrows( + OptionValidationException.class, + () -> + ConfigValidator.of(ReadonlyConfig.fromMap(config)) + .validate(new MaxcomputeSourceFactory().optionRule())); + Assertions.assertTrue(error.getMessage().contains(MaxcomputeSourceOptions.ENDPOINT.key())); + } + @Test void optionRule() { Assertions.assertNotNull((new MaxcomputeSourceFactory()).optionRule());
