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 d4c59bb1fcb Add SystemSchemaBuilderTest (#37087)
d4c59bb1fcb is described below
commit d4c59bb1fcb3d64917c1f99fe6d4989b2f194076
Author: Liang Zhang <[email protected]>
AuthorDate: Thu Nov 13 17:29:40 2025 +0800
Add SystemSchemaBuilderTest (#37087)
---
AGENTS.md | 6 +-
.../core/metadata/database/system/SystemTable.java | 49 +++++++++++++++
.../database/system/SystemDatabaseTest.java | 71 ++++++++++++++++++++++
.../metadata/database/system/SystemTableTest.java | 67 ++++++++++++++++++++
.../schema/builder/SystemSchemaBuilder.java | 15 +----
.../schema/builder/SystemSchemaBuilderTest.java | 32 +++++++++-
6 files changed, 224 insertions(+), 16 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index 53fe48d496c..5cb50e0028e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -37,8 +37,9 @@ Reference this flow when reasoning about new features or
debugging regressions.
Mention which topology you target, the registry used, and any compatibility
constraints (e.g., MySQL 5.7 vs 8.0) when proposing changes.
## Design Playbook
+- **Styles to favor:** elegant, minimal solutions—express intent with the
smallest construct that works, keep methods/tests lean, and avoid incidental
complexity.
- **Patterns to lean on:** builder/factory helpers in `infra`, SPI-based
extension points, immutable DTOs for plan descriptions, explicit strategy enums
for behavior toggles.
-- **Anti-patterns:** duplicating SQL parsing logic, bypassing metadata caches,
silent fallbacks when configuration is invalid, adding static singletons in
shared modules.
+- **Anti-patterns:** duplicating SQL parsing logic, bypassing metadata caches,
silent fallbacks when configuration is invalid, adding static singletons in
shared modules, over-engineering simple flows.
- **Known pitfalls:** routing regressions when skipping shadow rules, timezone
drift when mocking time poorly, forgetting to validate both standalone and
cluster (`mode`) settings, missing ASF headers in new files.
- **Success recipe:** describe why a change is needed, point to affected data
flow step, keep public APIs backwards compatible, and document defaults in
`docs`.
- **Case in point:** a prior shadow-rule regression was fixed by (1)
reproducing via `proxy` + sample config, (2) adding a `kernel` unit test
covering the skipped branch, (3) updating docs with the exact YAML flag—mirror
that discipline for new features.
@@ -69,6 +70,9 @@ Mention which topology you target, the registry used, and any
compatibility cons
- Mock databases, time, and network boundaries; build POJOs directly.
- When Jacoco fails, open `{module}/target/site/jacoco/index.html`, note
uncovered branches, and explain how new tests address them.
- Need a quick coverage view? Run `./mvnw -pl {module} -am -Djacoco.skip=false
test jacoco:report` and open `{module}/target/site/jacoco/index.html`.
+- Jacoco is disabled by default (the top-level POM sets `jacoco.skip=true`),
so explicitly pass `-Djacoco.skip=false` when you need coverage data, then run
`jacoco:report` for the same module scope.
+- Aggregator modules do not produce `jacoco.exec`; run tests under the
concrete module (`-pl {module} -am ... test`) before invoking `./mvnw -pl
{module} jacoco:report -Djacoco.skip=false`, otherwise the report step will be
skipped.
+- When static mocking is required, prefer
`@ExtendWith(AutoMockExtension.class)` plus `@StaticMockSettings` to manage
Mockito static mocks; avoid manual `mockStatic` blocks unless absolutely
necessary.
### Unit Test Style Recap
- Mirror production package paths, keep tests named `ClassNameTest`, and
express assertions through `assertXxxCondition` methods.
diff --git
a/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemTable.java
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemTable.java
new file mode 100644
index 00000000000..5c59706161d
--- /dev/null
+++
b/database/connector/core/src/main/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemTable.java
@@ -0,0 +1,49 @@
+/*
+ * 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.system;
+
+import lombok.RequiredArgsConstructor;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * System table.
+ */
+@RequiredArgsConstructor
+public final class SystemTable {
+
+ private final DatabaseType databaseType;
+
+ /**
+ * Judge whether supported system table.
+ *
+ * @param schemaName schema name
+ * @param tableName table name
+ * @return is supported system table or not
+ */
+ public boolean isSupportedSystemTable(final String schemaName, final
String tableName) {
+ if ("shardingsphere".equals(schemaName) &&
"cluster_information".equals(tableName)) {
+ return true;
+ }
+ Optional<DialectKernelSupportedSystemTable> kernelSupportedSystemTable
= DatabaseTypedSPILoader.findService(DialectKernelSupportedSystemTable.class,
databaseType);
+ return kernelSupportedSystemTable.map(optional ->
optional.getSchemaAndTablesMap().getOrDefault(schemaName,
Collections.emptySet()).contains(tableName)).orElse(false);
+ }
+}
diff --git
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemDatabaseTest.java
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemDatabaseTest.java
new file mode 100644
index 00000000000..d220789f620
--- /dev/null
+++
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemDatabaseTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.system;
+
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+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 java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class SystemDatabaseTest {
+
+ @Test
+ void assertGetSystemDatabases() {
+ DatabaseType databaseType = mock(DatabaseType.class);
+ DialectSystemDatabase dialectSystemDatabase =
mock(DialectSystemDatabase.class);
+ Collection<String> expected = Arrays.asList("sys_db", "meta_db");
+ when(dialectSystemDatabase.getSystemDatabases()).thenReturn(expected);
+ when(DatabaseTypedSPILoader.findService(DialectSystemDatabase.class,
databaseType)).thenReturn(Optional.of(dialectSystemDatabase));
+ SystemDatabase systemDatabase = new SystemDatabase(databaseType);
+ assertThat(systemDatabase.getSystemDatabases(), is(expected));
+ }
+
+ @Test
+ void assertGetSystemSchemasWithDatabaseName() {
+ DatabaseType databaseType = mock(DatabaseType.class);
+ DialectSystemDatabase dialectSystemDatabase =
mock(DialectSystemDatabase.class);
+ Collection<String> expected =
Collections.singletonList("information_schema");
+
when(dialectSystemDatabase.getSystemSchemas("postgres")).thenReturn(expected);
+ when(DatabaseTypedSPILoader.findService(DialectSystemDatabase.class,
databaseType)).thenReturn(Optional.of(dialectSystemDatabase));
+ SystemDatabase systemDatabase = new SystemDatabase(databaseType);
+ assertThat(systemDatabase.getSystemSchemas("postgres"), is(expected));
+ }
+
+ @Test
+ void assertGetSystemSchemasWhenSpiAbsent() {
+ DatabaseType databaseType = mock(DatabaseType.class);
+ when(DatabaseTypedSPILoader.findService(DialectSystemDatabase.class,
databaseType)).thenReturn(Optional.empty());
+ SystemDatabase systemDatabase = new SystemDatabase(databaseType);
+ assertTrue(systemDatabase.getSystemSchemas().isEmpty());
+ }
+}
diff --git
a/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemTableTest.java
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemTableTest.java
new file mode 100644
index 00000000000..92931c5ae86
--- /dev/null
+++
b/database/connector/core/src/test/java/org/apache/shardingsphere/database/connector/core/metadata/database/system/SystemTableTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.system;
+
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+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 java.util.Collections;
+import java.util.Optional;
+
+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(DatabaseTypedSPILoader.class)
+class SystemTableTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertIsSupportedSystemTableForClusterInformation() {
+ assertTrue(new
SystemTable(databaseType).isSupportedSystemTable("shardingsphere",
"cluster_information"));
+ }
+
+ @Test
+ void assertIsSupportedSystemTableWhenKernelSupported() {
+ DialectKernelSupportedSystemTable kernelSupportedSystemTable =
mock(DialectKernelSupportedSystemTable.class);
+
when(kernelSupportedSystemTable.getSchemaAndTablesMap()).thenReturn(Collections.singletonMap("information_schema",
Collections.singleton("columns")));
+
when(DatabaseTypedSPILoader.findService(DialectKernelSupportedSystemTable.class,
databaseType)).thenReturn(Optional.of(kernelSupportedSystemTable));
+ assertTrue(new
SystemTable(databaseType).isSupportedSystemTable("information_schema",
"columns"));
+ }
+
+ @Test
+ void assertIsNotSupportedSystemTableWhenKernelUnsupported() {
+ DialectKernelSupportedSystemTable kernelSupportedSystemTable =
mock(DialectKernelSupportedSystemTable.class);
+
when(kernelSupportedSystemTable.getSchemaAndTablesMap()).thenReturn(Collections.singletonMap("information_schema",
Collections.singleton("tables")));
+
when(DatabaseTypedSPILoader.findService(DialectKernelSupportedSystemTable.class,
databaseType)).thenReturn(Optional.of(kernelSupportedSystemTable));
+ assertFalse(new
SystemTable(databaseType).isSupportedSystemTable("information_schema",
"columns"));
+ }
+
+ @Test
+ void
assertIsNotSupportedSystemTableWhenDialectKernelSupportedSystemTableAbsent() {
+
when(DatabaseTypedSPILoader.findService(DialectKernelSupportedSystemTable.class,
databaseType)).thenReturn(Optional.empty());
+ assertFalse(new
SystemTable(databaseType).isSupportedSystemTable("shardingsphere",
"unknown_table"));
+ }
+}
diff --git
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilder.java
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilder.java
index c075043f8fd..1d493f3d6b1 100644
---
a/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilder.java
+++
b/infra/common/src/main/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilder.java
@@ -20,9 +20,8 @@ package
org.apache.shardingsphere.infra.metadata.database.schema.builder;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
-import
org.apache.shardingsphere.database.connector.core.metadata.database.system.DialectKernelSupportedSystemTable;
import
org.apache.shardingsphere.database.connector.core.metadata.database.system.SystemDatabase;
-import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.system.SystemTable;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
@@ -40,7 +39,6 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
-import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
@@ -79,20 +77,13 @@ public final class SystemSchemaBuilder {
private static ShardingSphereSchema createSchema(final String schemaName,
final DatabaseType databaseType, final boolean isSystemSchemaMetadataEnabled) {
Collection<ShardingSphereTable> tables = new LinkedList<>();
+ SystemTable systemTable = new SystemTable(databaseType);
for (InputStream each :
SystemSchemaManager.getAllInputStreams(databaseType.getType(), schemaName)) {
YamlShardingSphereTable metaData = new Yaml().loadAs(each,
YamlShardingSphereTable.class);
- if (isSystemSchemaMetadataEnabled ||
isSupportedSystemTable(databaseType, schemaName, metaData.getName())) {
+ if (isSystemSchemaMetadataEnabled ||
systemTable.isSupportedSystemTable(schemaName, metaData.getName())) {
tables.add(TABLE_SWAPPER.swapToObject(metaData));
}
}
return new ShardingSphereSchema(schemaName, tables,
Collections.emptyList());
}
-
- private static boolean isSupportedSystemTable(final DatabaseType
databaseType, final String schemaName, final String tableName) {
- if ("shardingsphere".equals(schemaName) &&
"cluster_information".equals(tableName)) {
- return true;
- }
- Optional<DialectKernelSupportedSystemTable> kernelSupportedSystemTable
= DatabaseTypedSPILoader.findService(DialectKernelSupportedSystemTable.class,
databaseType);
- return kernelSupportedSystemTable.map(optional ->
optional.getSchemaAndTablesMap().getOrDefault(schemaName,
Collections.emptySet()).contains(tableName)).orElse(false);
- }
}
diff --git
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilderTest.java
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilderTest.java
index fb803d7e34b..9f11590c541 100644
---
a/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilderTest.java
+++
b/infra/common/src/test/java/org/apache/shardingsphere/infra/metadata/database/schema/builder/SystemSchemaBuilderTest.java
@@ -19,8 +19,11 @@ package
org.apache.shardingsphere.infra.metadata.database.schema.builder;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import
org.apache.shardingsphere.infra.config.props.temporary.TemporaryConfigurationPropertyKey;
import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.infra.util.props.PropertiesBuilder;
+import org.apache.shardingsphere.infra.util.props.PropertiesBuilder.Property;
import org.junit.jupiter.api.Test;
import java.util.Map;
@@ -28,6 +31,7 @@ import java.util.Properties;
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;
class SystemSchemaBuilderTest {
@@ -35,7 +39,7 @@ class SystemSchemaBuilderTest {
@Test
void assertBuildForMySQL() {
DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "MySQL");
- ConfigurationProperties configProps = new ConfigurationProperties(new
Properties());
+ ConfigurationProperties configProps = new
ConfigurationProperties(PropertiesBuilder.build());
Map<String, ShardingSphereSchema> actualInformationSchema =
SystemSchemaBuilder.build("information_schema", databaseType, configProps);
assertThat(actualInformationSchema.size(), is(1));
assertTrue(actualInformationSchema.containsKey("information_schema"));
@@ -57,7 +61,7 @@ class SystemSchemaBuilderTest {
@Test
void assertBuildForPostgreSQL() {
DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "PostgreSQL");
- Map<String, ShardingSphereSchema> actual =
SystemSchemaBuilder.build("sharding_db", databaseType, new
ConfigurationProperties(new Properties()));
+ Map<String, ShardingSphereSchema> actual =
SystemSchemaBuilder.build("sharding_db", databaseType, new
ConfigurationProperties(PropertiesBuilder.build()));
assertThat(actual.size(), is(3));
assertTrue(actual.containsKey("information_schema"));
assertTrue(actual.containsKey("pg_catalog"));
@@ -70,7 +74,7 @@ class SystemSchemaBuilderTest {
@Test
void assertBuildForOpenGaussSQL() {
DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "openGauss");
- Map<String, ShardingSphereSchema> actual =
SystemSchemaBuilder.build("sharding_db", databaseType, new
ConfigurationProperties(new Properties()));
+ Map<String, ShardingSphereSchema> actual =
SystemSchemaBuilder.build("sharding_db", databaseType, new
ConfigurationProperties(PropertiesBuilder.build()));
assertThat(actual.size(), is(16));
assertTrue(actual.containsKey("pg_catalog"));
assertTrue(actual.containsKey("shardingsphere"));
@@ -78,4 +82,26 @@ class SystemSchemaBuilderTest {
assertThat(actual.get("pg_catalog").getAllTables().size(), is(240));
assertThat(actual.get("shardingsphere").getAllTables().size(), is(1));
}
+
+ @Test
+ void assertBuildForPostgreSQLWhenSystemSchemaMetadataDisabled() {
+ DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "PostgreSQL");
+ Properties props = PropertiesBuilder.build(new
Property(TemporaryConfigurationPropertyKey.SYSTEM_SCHEMA_METADATA_ASSEMBLY_ENABLED.getKey(),
Boolean.FALSE.toString()));
+ Map<String, ShardingSphereSchema> actual =
SystemSchemaBuilder.build("sharding_db", databaseType, new
ConfigurationProperties(props));
+ assertThat(actual.size(), is(3));
+ ShardingSphereSchema informationSchema =
actual.get("information_schema");
+ assertThat(informationSchema.getAllTables().size(), is(3));
+ assertTrue(informationSchema.containsTable("columns"));
+ assertTrue(informationSchema.containsTable("tables"));
+ assertTrue(informationSchema.containsTable("views"));
+ assertFalse(informationSchema.containsTable("attributes"));
+ ShardingSphereSchema pgCatalog = actual.get("pg_catalog");
+ assertThat(pgCatalog.getAllTables().size(), is(9));
+ assertTrue(pgCatalog.containsTable("pg_class"));
+ assertTrue(pgCatalog.containsTable("pg_tables"));
+ assertFalse(pgCatalog.containsTable("pg_indexes"));
+ ShardingSphereSchema shardingsphereSchema =
actual.get("shardingsphere");
+ assertThat(shardingsphereSchema.getAllTables().size(), is(1));
+ assertTrue(shardingsphereSchema.containsTable("cluster_information"));
+ }
}