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;
+    }
+}

Reply via email to