This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 0bae58eee21 Add full coverage for metadata loaders and privilege
checkers (#37587)
0bae58eee21 is described below
commit 0bae58eee213761951f17c4be308ac5fe285883f
Author: Liang Zhang <[email protected]>
AuthorDate: Wed Dec 31 00:55:36 2025 +0800
Add full coverage for metadata loaders and privilege checkers (#37587)
---
.../data/loader/type/SchemaMetaDataLoaderTest.java | 142 +++++++++++++++++++++
.../database/datatype/DataTypeRegistryTest.java | 102 +++++++++++++++
.../OpenGaussDatabasePrivilegeCheckerTest.java | 95 ++++++++++++++
database/connector/dialect/presto/pom.xml | 7 +
.../data/loader/PrestoMetaDataLoaderTest.java | 139 ++++++++++++++++++++
5 files changed, 485 insertions(+)
diff --git
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/SchemaMetaDataLoaderTest.java
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/SchemaMetaDataLoaderTest.java
new file mode 100644
index 00000000000..6ce10445a0a
--- /dev/null
+++
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/data/loader/type/SchemaMetaDataLoaderTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.database.connector.core.metadata.data.loader.type;
+
+import com.cedarsoftware.util.CaseInsensitiveSet;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.system.DialectSystemDatabase;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
+import org.mockito.MockedStatic;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class SchemaMetaDataLoaderTest {
+
+ private static final String[] TABLE_TYPES = {"TABLE", "PARTITIONED TABLE",
"VIEW", "SYSTEM TABLE", "SYSTEM VIEW"};
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private DataSource dataSourceWithoutDefaultSchema;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private DataSource dataSourceWithDefaultSchema;
+
+ @Test
+ void assertLoadSchemaTableNamesWithoutDefaultSchema() throws SQLException {
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+ when(schemaOption.getDefaultSchema()).thenReturn(Optional.empty());
+ when(schemaOption.getSchema(any())).thenReturn("public");
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mock(DialectDatabaseMetaData.class);
+
when(dialectDatabaseMetaData.getSchemaOption()).thenReturn(schemaOption);
+ try (MockedStatic<DatabaseTypedSPILoader> databaseTypedSPILoader =
mockStatic(DatabaseTypedSPILoader.class)) {
+ databaseTypedSPILoader.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ try (MockedStatic<TypedSPILoader> typedSPILoader =
mockStatic(TypedSPILoader.class)) {
+ typedSPILoader.when(() ->
TypedSPILoader.getService(DialectDatabaseMetaData.class,
null)).thenReturn(dialectDatabaseMetaData);
+ Connection connection =
dataSourceWithoutDefaultSchema.getConnection();
+ when(connection.getCatalog()).thenReturn("catalog");
+ ResultSet tableResultSet = mock(ResultSet.class);
+ when(tableResultSet.next()).thenReturn(true, true, true, true,
true, false);
+ when(tableResultSet.getString("TABLE_NAME")).thenReturn("tbl",
"$tbl", "/tbl", "##tbl", "excluded_tbl");
+ when(connection.getMetaData().getTables("catalog", "public",
null, TABLE_TYPES)).thenReturn(tableResultSet);
+ Map<String, Collection<String>> actual = new
SchemaMetaDataLoader(databaseType)
+ .loadSchemaTableNames("logic_db",
dataSourceWithoutDefaultSchema, Collections.singleton("excluded_tbl"));
+ Map<String, Collection<String>> expected =
Collections.singletonMap("logic_db", new
CaseInsensitiveSet<>(Collections.singleton("tbl")));
+ assertThat(actual, is(expected));
+ }
+ }
+ }
+
+ @Test
+ void assertLoadSchemaTableNamesWithDefaultSchema() throws SQLException {
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.of("public"));
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mock(DialectDatabaseMetaData.class);
+
when(dialectDatabaseMetaData.getSchemaOption()).thenReturn(schemaOption);
+ DialectSystemDatabase dialectSystemDatabase =
mock(DialectSystemDatabase.class);
+
when(dialectSystemDatabase.getSystemSchemas()).thenReturn(Collections.singleton("sys"));
+ try (MockedStatic<DatabaseTypedSPILoader> databaseTypedSPILoader =
mockStatic(DatabaseTypedSPILoader.class)) {
+ databaseTypedSPILoader.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ databaseTypedSPILoader.when(() ->
DatabaseTypedSPILoader.findService(DialectSystemDatabase.class,
databaseType)).thenReturn(Optional.of(dialectSystemDatabase));
+ try (MockedStatic<TypedSPILoader> typedSPILoader =
mockStatic(TypedSPILoader.class)) {
+ typedSPILoader.when(() ->
TypedSPILoader.getService(DialectDatabaseMetaData.class,
null)).thenReturn(dialectDatabaseMetaData);
+ Connection connection =
dataSourceWithDefaultSchema.getConnection();
+ when(connection.getCatalog()).thenReturn("catalog_2");
+ ResultSet schemaResultSet = mock(ResultSet.class);
+ when(schemaResultSet.next()).thenReturn(true, true, false);
+
when(schemaResultSet.getString("TABLE_SCHEM")).thenReturn("sys", "user_schema");
+
when(connection.getMetaData().getSchemas()).thenReturn(schemaResultSet);
+ ResultSet tableResultSet = mock(ResultSet.class);
+ when(tableResultSet.next()).thenReturn(true, false);
+
when(tableResultSet.getString("TABLE_NAME")).thenReturn("tbl_visible");
+ when(connection.getMetaData().getTables("catalog_2",
"user_schema", null, TABLE_TYPES)).thenReturn(tableResultSet);
+ Map<String, Collection<String>> actual = new
SchemaMetaDataLoader(databaseType).loadSchemaTableNames("logic_db_2",
dataSourceWithDefaultSchema, Collections.emptyList());
+ Map<String, Collection<String>> expected =
Collections.singletonMap("user_schema", new
CaseInsensitiveSet<>(Collections.singleton("tbl_visible")));
+ assertThat(actual, is(expected));
+ }
+ }
+ }
+
+ @Test
+ void assertLoadSchemaNames() throws SQLException {
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.of("public"));
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mock(DialectDatabaseMetaData.class);
+
when(dialectDatabaseMetaData.getSchemaOption()).thenReturn(schemaOption);
+ DialectSystemDatabase dialectSystemDatabase =
mock(DialectSystemDatabase.class);
+
when(dialectSystemDatabase.getSystemSchemas()).thenReturn(Collections.singleton("information_schema"));
+ try (MockedStatic<DatabaseTypedSPILoader> databaseTypedSPILoader =
mockStatic(DatabaseTypedSPILoader.class)) {
+ databaseTypedSPILoader.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ databaseTypedSPILoader.when(() ->
DatabaseTypedSPILoader.findService(DialectSystemDatabase.class,
databaseType)).thenReturn(Optional.of(dialectSystemDatabase));
+ try (MockedStatic<TypedSPILoader> typedSPILoader =
mockStatic(TypedSPILoader.class)) {
+ typedSPILoader.when(() ->
TypedSPILoader.getService(DialectDatabaseMetaData.class,
null)).thenReturn(dialectDatabaseMetaData);
+ Connection connection = mock(Connection.class,
RETURNS_DEEP_STUBS);
+ ResultSet resultSet = mock(ResultSet.class);
+ when(resultSet.next()).thenReturn(true, false);
+
when(resultSet.getString("TABLE_SCHEM")).thenReturn("information_schema");
+
when(connection.getMetaData().getSchemas()).thenReturn(resultSet);
+ when(connection.getSchema()).thenReturn("current_schema");
+ assertThat(new
SchemaMetaDataLoader(databaseType).loadSchemaNames(connection),
is(Collections.singletonList("current_schema")));
+ }
+ }
+ }
+}
diff --git
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/datatype/DataTypeRegistryTest.java
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/datatype/DataTypeRegistryTest.java
new file mode 100644
index 00000000000..7e3c5a17005
--- /dev/null
+++
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/datatype/DataTypeRegistryTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.database.connector.core.metadata.database.datatype;
+
+import com.cedarsoftware.util.CaseInsensitiveMap;
+import lombok.SneakyThrows;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.infra.exception.external.sql.type.wrapper.SQLWrapperException;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.internal.configuration.plugins.Plugins;
+
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+
+class DataTypeRegistryTest {
+
+ private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+
+ @AfterEach
+ void cleanUp() {
+ getDataTypes().clear();
+ }
+
+ @SuppressWarnings("unchecked")
+ @SneakyThrows(ReflectiveOperationException.class)
+ private Map<String, Map<String, Integer>> getDataTypes() {
+ return (Map<String, Map<String, Integer>>)
Plugins.getMemberAccessor().get(DataTypeRegistry.class.getDeclaredField("DATA_TYPES"),
null);
+ }
+
+ @Test
+ void assertLoad() throws SQLException {
+ ResultSet resultSet = mock(ResultSet.class);
+ when(resultSet.next()).thenReturn(true, true, false);
+ when(resultSet.getString("TYPE_NAME")).thenReturn("int", "varchar");
+ when(resultSet.getInt("DATA_TYPE")).thenReturn(Types.INTEGER,
Types.VARCHAR);
+ DataSource dataSource = mock(DataSource.class, RETURNS_DEEP_STUBS);
+
when(dataSource.getConnection().getMetaData().getTypeInfo()).thenReturn(resultSet);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mock(DialectDatabaseMetaData.class, RETURNS_DEEP_STUBS);
+
when(dialectDatabaseMetaData.getDataTypeOption().getExtraDataTypes()).thenReturn(Collections.singletonMap("EXTRA_TYPE",
Types.OTHER));
+ try (MockedStatic<DatabaseTypedSPILoader> databaseTypedSPILoader =
mockStatic(DatabaseTypedSPILoader.class)) {
+ databaseTypedSPILoader.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ try (MockedStatic<TypedSPILoader> typedSPILoader =
mockStatic(TypedSPILoader.class)) {
+ typedSPILoader.when(() ->
TypedSPILoader.getService(DatabaseType.class,
"FIXTURE")).thenReturn(databaseType);
+ typedSPILoader.when(() ->
TypedSPILoader.getService(DialectDatabaseMetaData.class,
null)).thenReturn(dialectDatabaseMetaData);
+ DataTypeRegistry.load(dataSource, "FIXTURE");
+ assertThat(DataTypeRegistry.getDataType("FIXTURE", "int"),
is(Optional.of(Types.INTEGER)));
+ assertThat(DataTypeRegistry.getDataType("FIXTURE",
"extra_type"), is(Optional.of(Types.OTHER)));
+ DataTypeRegistry.load(mock(DataSource.class,
RETURNS_DEEP_STUBS), "FIXTURE");
+ DataSource brokenDataSource = mock(DataSource.class);
+
when(brokenDataSource.getConnection()).thenThrow(SQLException.class);
+ assertThrows(SQLWrapperException.class, () ->
DataTypeRegistry.load(brokenDataSource, "broken"));
+ }
+ }
+ }
+
+ @Test
+ void assertGetDataTypeWhenDatabaseMissing() {
+ assertFalse(DataTypeRegistry.getDataType("unknown",
"int").isPresent());
+ }
+
+ @Test
+ void assertGetDataType() {
+ Map<String, Map<String, Integer>> dataTypes = getDataTypes();
+ dataTypes.put("test_db", new
CaseInsensitiveMap<>(Collections.singletonMap("varchar", Types.VARCHAR)));
+ assertThat(DataTypeRegistry.getDataType("test_db", "varchar"),
is(Optional.of(Types.VARCHAR)));
+ assertFalse(DataTypeRegistry.getDataType("test_db",
"missing").isPresent());
+ }
+}
diff --git
a/database/connector/dialect/opengauss/src/test/java/org/apache/shardingsphere/database/connector/opengauss/checker/OpenGaussDatabasePrivilegeCheckerTest.java
b/database/connector/dialect/opengauss/src/test/java/org/apache/shardingsphere/database/connector/opengauss/checker/OpenGaussDatabasePrivilegeCheckerTest.java
new file mode 100644
index 00000000000..5b0853a3323
--- /dev/null
+++
b/database/connector/dialect/opengauss/src/test/java/org/apache/shardingsphere/database/connector/opengauss/checker/OpenGaussDatabasePrivilegeCheckerTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.database.connector.opengauss.checker;
+
+import
org.apache.shardingsphere.database.connector.core.checker.DialectDatabasePrivilegeChecker;
+import
org.apache.shardingsphere.database.connector.core.checker.PrivilegeCheckType;
+import
org.apache.shardingsphere.database.connector.core.exception.CheckDatabaseEnvironmentFailedException;
+import
org.apache.shardingsphere.database.connector.core.exception.MissingRequiredPrivilegeException;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.Test;
+
+import javax.sql.DataSource;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class OpenGaussDatabasePrivilegeCheckerTest {
+
+ private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "openGauss");
+
+ private final DialectDatabasePrivilegeChecker checker =
DatabaseTypedSPILoader.getService(DialectDatabasePrivilegeChecker.class,
databaseType);
+
+ @Test
+ void assertCheckWithNoneType() {
+ assertDoesNotThrow(() -> checker.check(mock(DataSource.class),
PrivilegeCheckType.NONE));
+ }
+
+ @Test
+ void assertCheckWithSuperRole() {
+ assertDoesNotThrow(() -> checker.check(mockPipelineDataSource("admin",
"t", "f"), PrivilegeCheckType.PIPELINE));
+ }
+
+ @Test
+ void assertCheckWithReplicationRole() {
+ assertDoesNotThrow(() ->
checker.check(mockPipelineDataSource("replication_user", "f", "t"),
PrivilegeCheckType.PIPELINE));
+ }
+
+ @Test
+ void assertCheckWhenPrivilegeMissing() {
+ MissingRequiredPrivilegeException actual =
assertThrows(MissingRequiredPrivilegeException.class,
+ () -> checker.check(mockPipelineDataSource("normal", "f",
"f"), PrivilegeCheckType.PIPELINE));
+ assertThat(actual.getMessage(), is("Missing required privilege(s)
`REPLICATION`"));
+ }
+
+ @Test
+ void assertCheckWhenSQLExceptionThrown() throws SQLException {
+ DataSource dataSource = mock(DataSource.class);
+ when(dataSource.getConnection()).thenThrow(SQLException.class);
+ assertThrows(CheckDatabaseEnvironmentFailedException.class, () ->
checker.check(dataSource, PrivilegeCheckType.PIPELINE));
+ }
+
+ @SuppressWarnings({"JDBCResourceOpenedButNotSafelyClosed", "resource"})
+ private DataSource mockPipelineDataSource(final String username, final
String isSuperRole, final String isReplicationRole) throws SQLException {
+ DataSource result = mock(DataSource.class, RETURNS_DEEP_STUBS);
+
when(result.getConnection().getMetaData().getUserName()).thenReturn(username);
+ PreparedStatement preparedStatement =
result.getConnection().prepareStatement("SELECT * FROM pg_roles WHERE rolname =
?");
+ ResultSet resultSet = mockResultSet(isSuperRole, isReplicationRole);
+ when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ return result;
+ }
+
+ private ResultSet mockResultSet(final String isSuperRole, final String
isReplicationRole) throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true);
+ when(result.getString("rolsuper")).thenReturn(isSuperRole);
+ when(result.getString("rolreplication")).thenReturn(isReplicationRole);
+ when(result.getString("rolsystemadmin")).thenReturn("f");
+ return result;
+ }
+}
diff --git a/database/connector/dialect/presto/pom.xml
b/database/connector/dialect/presto/pom.xml
index 4eb24972509..df7c9eab823 100644
--- a/database/connector/dialect/presto/pom.xml
+++ b/database/connector/dialect/presto/pom.xml
@@ -32,6 +32,13 @@
<artifactId>shardingsphere-database-connector-core</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.shardingsphere</groupId>
+ <artifactId>shardingsphere-test-infra-framework</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-jdbc</artifactId>
diff --git
a/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
b/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
new file mode 100644
index 00000000000..46c9d3a98ed
--- /dev/null
+++
b/database/connector/dialect/presto/src/test/java/org/apache/shardingsphere/database/connector/presto/metadata/data/loader/PrestoMetaDataLoaderTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.database.connector.presto.metadata.data.loader;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.data.loader.DialectMetaDataLoader;
+import
org.apache.shardingsphere.database.connector.core.metadata.data.loader.MetaDataLoaderMaterial;
+import
org.apache.shardingsphere.database.connector.core.metadata.data.model.ColumnMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.data.model.SchemaMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.data.model.TableMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.datatype.DataTypeRegistry;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DataTypeRegistry.class)
+class PrestoMetaDataLoaderTest {
+
+ private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "Presto");
+
+ private final DialectMetaDataLoader loader =
DatabaseTypedSPILoader.getService(DialectMetaDataLoader.class, databaseType);
+
+ @Test
+ void assertLoadWithoutTableFilter() throws SQLException {
+ Connection connectionWithoutTables = mockConnectionWithoutTables();
+ DataSource dataSource = mock(DataSource.class);
+ when(dataSource.getConnection()).thenReturn(connectionWithoutTables);
+ when(DataTypeRegistry.getDataType("Presto",
"int")).thenReturn(Optional.of(Types.INTEGER));
+ when(DataTypeRegistry.getDataType("Presto",
"varchar")).thenReturn(Optional.empty());
+ Collection<SchemaMetaData> actualWithoutTables = loader.load(new
MetaDataLoaderMaterial(Collections.emptyList(), "ds_0", dataSource,
databaseType, "def_schema"));
+ SchemaMetaData schemaMetaDataWithoutTables =
actualWithoutTables.iterator().next();
+ assertThat(schemaMetaDataWithoutTables.getName(), is("def_schema"));
+ TableMetaData tableMetaDataWithoutTables =
schemaMetaDataWithoutTables.getTables().iterator().next();
+ assertThat(tableMetaDataWithoutTables.getName(), is("tbl_one"));
+ Iterator<ColumnMetaData> columnIterator =
tableMetaDataWithoutTables.getColumns().iterator();
+ ColumnMetaData firstColumn = columnIterator.next();
+ assertThat(firstColumn.getName(), is("id"));
+ assertThat(firstColumn.getDataType(), is(Types.INTEGER));
+ assertTrue(firstColumn.isNullable());
+ ColumnMetaData secondColumn = columnIterator.next();
+ assertThat(secondColumn.getName(), is("name"));
+ assertThat(secondColumn.getDataType(), is(Types.OTHER));
+ assertFalse(secondColumn.isNullable());
+ }
+
+ @Test
+ void assertLoadWithTableFilter() throws SQLException {
+ Connection connectionWithTables = mockConnectionWithTables();
+ DataSource dataSource = mock(DataSource.class);
+ when(dataSource.getConnection()).thenReturn(connectionWithTables);
+ when(DataTypeRegistry.getDataType("Presto",
"json")).thenReturn(Optional.of(Types.JAVA_OBJECT));
+ Collection<SchemaMetaData> actualWithTables = loader.load(new
MetaDataLoaderMaterial(Collections.singletonList("target_table"), "ds_0",
dataSource, databaseType, "def_schema"));
+ SchemaMetaData schemaMetaDataWithTables =
actualWithTables.iterator().next();
+ TableMetaData tableMetaDataWithTables =
schemaMetaDataWithTables.getTables().iterator().next();
+ ColumnMetaData payloadColumn =
tableMetaDataWithTables.getColumns().iterator().next();
+ assertThat(tableMetaDataWithTables.getName(), is("target_table"));
+ assertThat(payloadColumn.getDataType(), is(Types.JAVA_OBJECT));
+ }
+
+ private Connection mockConnectionWithoutTables() throws SQLException {
+ Connection result = mock(Connection.class);
+ PreparedStatement preparedStatement = mock(PreparedStatement.class);
+ ResultSet resultSet = mockResultSetWithoutTables();
+ when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ when(result.getCatalog()).thenReturn("catalog_one");
+ String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG=? ORDER BY
ORDINAL_POSITION";
+ when(result.prepareStatement(sql)).thenReturn(preparedStatement);
+ return result;
+ }
+
+ private ResultSet mockResultSetWithoutTables() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, true, false);
+ when(result.getString("TABLE_NAME")).thenReturn("tbl_one", "tbl_one");
+ when(result.getString("COLUMN_NAME")).thenReturn("id", "name");
+ when(result.getString("DATA_TYPE")).thenReturn("int", "varchar");
+ when(result.getString("IS_NULLABLE")).thenReturn("YES", "NO");
+ return result;
+ }
+
+ private Connection mockConnectionWithTables() throws SQLException {
+ Connection result = mock(Connection.class);
+ PreparedStatement preparedStatement = mock(PreparedStatement.class);
+ ResultSet resultSet = mockResultSetWithTables();
+ when(preparedStatement.executeQuery()).thenReturn(resultSet);
+ String sql = "SELECT
TABLE_CATALOG,TABLE_NAME,COLUMN_NAME,DATA_TYPE,ORDINAL_POSITION,IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS "
+ + "WHERE TABLE_CATALOG=? AND UPPER(TABLE_NAME) IN
('TARGET_TABLE') ORDER BY ORDINAL_POSITION";
+ when(result.prepareStatement(sql)).thenReturn(preparedStatement);
+ when(result.getCatalog()).thenReturn("catalog_two");
+ return result;
+ }
+
+ private ResultSet mockResultSetWithTables() throws SQLException {
+ ResultSet result = mock(ResultSet.class);
+ when(result.next()).thenReturn(true, false);
+ when(result.getString("TABLE_NAME")).thenReturn("target_table");
+ when(result.getString("COLUMN_NAME")).thenReturn("payload");
+ when(result.getString("DATA_TYPE")).thenReturn("json");
+ when(result.getString("IS_NULLABLE")).thenReturn("NO");
+ return result;
+ }
+}