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 604b315abbe Add unit tests for DatabaseRuleConfigurationManager and 
DatabaseRuleItemManager (#37260)
604b315abbe is described below

commit 604b315abbe1da0d7e82abdf02715685e104fbf2
Author: Liang Zhang <[email protected]>
AuthorDate: Tue Dec 2 23:35:02 2025 +0800

    Add unit tests for DatabaseRuleConfigurationManager and 
DatabaseRuleItemManager (#37260)
    
    * Add unit tests for DatabaseRuleConfigurationManager and 
DatabaseRuleItemManager
    
    * Add unit tests for DatabaseRuleConfigurationManager and 
DatabaseRuleItemManager
    
    * Add unit tests for DatabaseRuleConfigurationManager and 
DatabaseRuleItemManager
    
    * Add InternalClickHouseParserIT
---
 AGENTS.md                                          |   4 +-
 .../rule/DatabaseRuleConfigurationManagerTest.java | 200 +++++++++++++++++++++
 .../manager/rule/DatabaseRuleItemManagerTest.java  | 126 +++++++++++++
 .../rule/GlobalConfigurationManagerTest.java       | 152 ++++++++++++++++
 .../it/sql/parser/internal/cases/sql/SQLCases.java |   3 +-
 .../InternalClickHouseParserIT.java}               |   8 +-
 .../sql/parser/presto/InternalPrestoParserIT.java  |   2 -
 7 files changed, 486 insertions(+), 9 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 8b72e702087..593305aa58f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -19,6 +19,7 @@ This guide is written **for AI coding agents only**. Follow 
it literally; improv
 - **Code Quality**:
     - Use clear naming and reasonable abstractions.
     - Delete unused code; when changing functionality, remove legacy 
compatibility shims.
+    - Keep variable declarations adjacent to first use; if a value must be 
retained, declare it `final` to satisfy Checkstyle 
VariableDeclarationUsageDistance.
 - **Complete Implementation**: no MVPs/placeholders/TODOs—deliver fully 
runnable solutions.
 
 ### Performance Standards
@@ -199,6 +200,7 @@ Always state which topology, registry, and engine versions 
(e.g., MySQL 5.7 vs 8
 - **Go-to commands:** `./mvnw clean install -B -T1C -Pcheck` (full build), 
`./mvnw test -pl <module>[-am]` (scoped unit tests), `./mvnw spotless:apply 
-Pcheck [-pl <module>]` (format), `./mvnw -pl <module> -DskipITs 
-Dspotless.skip=true -Dtest=ClassName test` (fast verification), and `./mvnw 
-pl proxy -am -DskipTests package` (proxy packaging/perf smoke).
 - **Coverage verification:** before finishing any task that adds or changes 
tests, run the coverage check (e.g., `./mvnw test jacoco:check@jacoco-check 
-Pcoverage-check` or scoped `-pl <module> -am`) and explicitly confirm whether 
the targeted code reaches 100% when required.
 - **Checkstyle command:** run `./mvnw checkstyle:check -Pcheck` (or with `-pl 
<module> -am -Pcheck` for scoped runs) unless explicitly instructed otherwise.
+- **Default verification commands:** prefer scoped runs `./mvnw -pl <module> 
-am -DskipITs -Djacoco.skip=false -Dsurefire.failIfNoSpecifiedTests=false test 
jacoco:report` for coverage and `./mvnw -pl <module> checkstyle:check -Pcheck` 
for style; avoid whole-repo builds unless the user requests them.
 - **Testing ground rules:** JUnit 5 + Mockito, `ClassNameTest` naming, 
Arrange–Act–Assert structure, mocks for databases/time/network, reset static 
caches between cases, and prefer existing swapper/helpers for complex configs.
 - **Coverage discipline:** run Jacoco (`./mvnw -pl <module> -am 
-Djacoco.skip=false test jacoco:report`) when coverage is in question; describe 
any uncovered branches with file/line reasoning.
 - **Branch-focused work:** when asked for “minimal branch coverage” or 
similar, list every branch upfront, map each to a single test, and document 
unreachable code explicitly instead of adding redundant cases.
@@ -244,7 +246,7 @@ Always state which topology, registry, and engine versions 
(e.g., MySQL 5.7 vs 8
 - Mock heavy dependencies (database/cache/registry/network) and prefer mocking 
over building deep object graphs; avoid `RETURNS_DEEP_STUBS` unless chained 
interactions demand it.
 - Before changing how mocks are created, scan the repository for similar tests 
(e.g., other rule decorators or executor tests) and reuse their proven mocking 
pattern instead of inventing a new structure.
 - When constructors hide collaborators, use `Plugins.getMemberAccessor()` to 
inject mocks and document why SPI creation is bypassed.
-- If a test already uses `@ExtendWith(AutoMockExtension.class)`, always 
declare the needed static collaborators via `@StaticMockSettings` instead of 
hand-written `mockStatic` blocks; justify any exception explicitly in the plan 
before coding.
+- If a test already uses `@ExtendWith(AutoMockExtension.class)`, always 
declare the needed static collaborators via `@StaticMockSettings` instead of 
hand-written `mockStatic` blocks; when a class appears in 
`@StaticMockSettings`, do not call `mockStatic` on it—directly stub via 
`when(...)` (cast to `TypedSPI` if needed) to avoid ClassCast/duplicate-mock 
issues; justify any exception explicitly in the plan before coding.
 - Before adding coverage to a utility with multiple return paths, list every 
branch (no rule, non-Single config, wildcard blocks, missing data node, 
positive path, collection overload) and map each to a test; update the plan 
whenever this checklist changes.
 - Prefer imports over fully-qualified class names inside code and tests; if a 
class is used, add an import rather than using the full package path inline.
 - Before coding tests, prepare a concise branch-and-data checklist (all 
branches, inputs, expected outputs) and keep the plan in sync when the 
checklist changes.
diff --git 
a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/DatabaseRuleConfigurationManagerTest.java
 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/DatabaseRuleConfigurationManagerTest.java
new file mode 100644
index 00000000000..a09f933ad43
--- /dev/null
+++ 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/DatabaseRuleConfigurationManagerTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.mode.metadata.manager.rule;
+
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
+import org.apache.shardingsphere.infra.rule.PartialRuleUpdateSupported;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import 
org.apache.shardingsphere.infra.rule.builder.database.DatabaseRulesBuilder;
+import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import org.apache.shardingsphere.mode.metadata.factory.MetaDataContextsFactory;
+import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistFacade;
+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 org.mockito.MockedConstruction;
+
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseRulesBuilder.class)
+class DatabaseRuleConfigurationManagerTest {
+    
+    private static final String DATABASE_NAME = "foo_db";
+    
+    @Test
+    void assertRefreshWithPartialUpdateAndRebuild() throws SQLException {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class);
+        ShardingSphereRule closableRule = mock(ShardingSphereRule.class, 
withSettings().extraInterfaces(PartialRuleUpdateSupported.class, 
AutoCloseable.class));
+        when(closableRule.getConfiguration()).thenReturn(ruleConfig);
+        PartialRuleUpdateSupported updater = (PartialRuleUpdateSupported) 
closableRule;
+        when(updater.partialUpdate(ruleConfig)).thenReturn(true);
+        ShardingSphereRule nonClosableRule = mock(ShardingSphereRule.class);
+        
when(nonClosableRule.getConfiguration()).thenReturn(mock(RuleConfiguration.class,
 withSettings().extraInterfaces(Cloneable.class)));
+        RuleMetaData ruleMetaData = new RuleMetaData(new 
LinkedList<>(Arrays.asList(closableRule, nonClosableRule)));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getRuleMetaData()).thenReturn(ruleMetaData);
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        ShardingSphereRule rebuiltRule = mock(ShardingSphereRule.class);
+        try (
+                MockedConstruction<MetaDataContextsFactory> ignored = 
mockConstruction(MetaDataContextsFactory.class,
+                        (mock, context) -> 
when(mock.createByAlterRule(eq(DATABASE_NAME), eq(false), 
any(Collection.class), 
eq(metaDataContexts))).thenReturn(mock(MetaDataContexts.class)))) {
+            when(DatabaseRulesBuilder.build(eq(DATABASE_NAME), any(), any(), 
eq(ruleConfig), any(), any())).thenReturn(rebuiltRule);
+            new DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, true);
+            verify((PartialRuleUpdateSupported) 
closableRule).updateConfiguration(ruleConfig);
+            verify(metaDataContexts).update(any(MetaDataContexts.class));
+            assertDoesNotThrow(() -> verify((AutoCloseable) 
closableRule).close());
+        }
+    }
+    
+    @Test
+    void assertRefreshWithPartialUpdateSkipMetadata() throws SQLException {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule partialRule = mock(ShardingSphereRule.class, 
withSettings().extraInterfaces(PartialRuleUpdateSupported.class));
+        when(partialRule.getConfiguration()).thenReturn(ruleConfig);
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+        when(database.getRuleMetaData()).thenReturn(new 
RuleMetaData(Collections.singleton(partialRule)));
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        new DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, true);
+        verify((PartialRuleUpdateSupported) 
partialRule).updateConfiguration(ruleConfig);
+        verify(metaDataContexts, never()).update(any(MetaDataContexts.class));
+    }
+    
+    @Test
+    void assertRefreshWithPartialUpdateWithoutRebuild() throws SQLException {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule partialRule = mock(ShardingSphereRule.class, 
withSettings().extraInterfaces(PartialRuleUpdateSupported.class));
+        when(partialRule.getConfiguration()).thenReturn(ruleConfig);
+        PartialRuleUpdateSupported updater = (PartialRuleUpdateSupported) 
partialRule;
+        when(updater.partialUpdate(ruleConfig)).thenReturn(true);
+        RuleMetaData ruleMetaData = new RuleMetaData(new 
LinkedList<>(Collections.singleton(partialRule)));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getRuleMetaData()).thenReturn(ruleMetaData);
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        try (
+                MockedConstruction<MetaDataContextsFactory> ignored = 
mockConstruction(MetaDataContextsFactory.class,
+                        (mock, context) -> 
when(mock.createByAlterRule(eq(DATABASE_NAME), eq(false), 
any(Collection.class), 
eq(metaDataContexts))).thenReturn(mock(MetaDataContexts.class)))) {
+            new DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, false);
+            verify(metaDataContexts).update(any(MetaDataContexts.class));
+            verify(updater).updateConfiguration(ruleConfig);
+        }
+    }
+    
+    @Test
+    void assertRefreshWithoutExistingRuleAndWithoutRebuild() throws 
SQLException {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule otherRule = mock(ShardingSphereRule.class);
+        
when(otherRule.getConfiguration()).thenReturn(mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Cloneable.class)));
+        RuleMetaData ruleMetaData = new 
RuleMetaData(Collections.singleton(otherRule));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getRuleMetaData()).thenReturn(ruleMetaData);
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        try (
+                MockedConstruction<MetaDataContextsFactory> ignored = 
mockConstruction(MetaDataContextsFactory.class,
+                        (mock, context) -> 
when(mock.createByAlterRule(eq(DATABASE_NAME), eq(false), 
any(Collection.class), 
eq(metaDataContexts))).thenReturn(mock(MetaDataContexts.class)))) {
+            new DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, false);
+            verify(metaDataContexts).update(any(MetaDataContexts.class));
+        }
+    }
+    
+    @Test
+    void assertRefreshWithExistingNonPartialRule() throws SQLException {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule existingRule = mock(ShardingSphereRule.class);
+        when(existingRule.getConfiguration()).thenReturn(ruleConfig);
+        RuleMetaData ruleMetaData = new 
RuleMetaData(Collections.singleton(existingRule));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getRuleMetaData()).thenReturn(ruleMetaData);
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        ShardingSphereRule rebuiltRule = mock(ShardingSphereRule.class);
+        try (
+                MockedConstruction<MetaDataContextsFactory> ignored = 
mockConstruction(MetaDataContextsFactory.class,
+                        (mock, context) -> 
when(mock.createByAlterRule(eq(DATABASE_NAME), eq(false), 
any(Collection.class), 
eq(metaDataContexts))).thenReturn(mock(MetaDataContexts.class)))) {
+            when(DatabaseRulesBuilder.build(eq(DATABASE_NAME), any(), any(), 
eq(ruleConfig), any(), any())).thenReturn(rebuiltRule);
+            new DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, true);
+            verify(metaDataContexts).update(any(MetaDataContexts.class));
+        }
+    }
+    
+    @Test
+    void assertRefreshWrapsException() {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule rule = mock(ShardingSphereRule.class);
+        when(rule.getConfiguration()).thenReturn(ruleConfig);
+        RuleMetaData ruleMetaData = new 
RuleMetaData(Collections.singleton(rule));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getRuleMetaData()).thenReturn(ruleMetaData);
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        try (
+                MockedConstruction<MetaDataContextsFactory> ignored = 
mockConstruction(MetaDataContextsFactory.class,
+                        (mock, context) -> 
when(mock.createByAlterRule(eq(DATABASE_NAME), eq(false), 
any(Collection.class), eq(metaDataContexts))).thenThrow(new 
SQLException("failed")))) {
+            assertThrows(SQLException.class,
+                    () -> new 
DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, false));
+        }
+    }
+    
+    @Test
+    void assertRefreshThrowsWhenCloseOriginalRuleFailed() throws Exception {
+        RuleConfiguration ruleConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule closableRule = mock(ShardingSphereRule.class, 
withSettings().extraInterfaces(PartialRuleUpdateSupported.class, 
AutoCloseable.class));
+        when(closableRule.getConfiguration()).thenReturn(ruleConfig);
+        PartialRuleUpdateSupported updater = (PartialRuleUpdateSupported) 
closableRule;
+        when(updater.partialUpdate(ruleConfig)).thenReturn(true);
+        doThrow(Exception.class).when((AutoCloseable) closableRule).close();
+        RuleMetaData ruleMetaData = new RuleMetaData(new 
LinkedList<>(Collections.singleton(closableRule)));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getRuleMetaData()).thenReturn(ruleMetaData);
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getDatabase(DATABASE_NAME)).thenReturn(database);
+        try (
+                MockedConstruction<MetaDataContextsFactory> ignored = 
mockConstruction(MetaDataContextsFactory.class,
+                        (mock, context) -> 
when(mock.createByAlterRule(eq(DATABASE_NAME), eq(false), 
any(Collection.class), 
eq(metaDataContexts))).thenReturn(mock(MetaDataContexts.class)))) {
+            assertThrows(Exception.class,
+                    () -> new 
DatabaseRuleConfigurationManager(metaDataContexts, 
mock(ComputeNodeInstanceContext.class), 
mock(MetaDataPersistFacade.class)).refresh(DATABASE_NAME, ruleConfig, false));
+        }
+    }
+}
diff --git 
a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/DatabaseRuleItemManagerTest.java
 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/DatabaseRuleItemManagerTest.java
new file mode 100644
index 00000000000..67c33babfc8
--- /dev/null
+++ 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/DatabaseRuleItemManagerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.mode.metadata.manager.rule;
+
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
+import 
org.apache.shardingsphere.infra.config.rule.checker.DatabaseRuleConfigurationEmptyChecker;
+import 
org.apache.shardingsphere.infra.config.rule.scope.DatabaseRuleConfiguration;
+import 
org.apache.shardingsphere.infra.exception.external.sql.type.wrapper.SQLWrapperException;
+import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPI;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistFacade;
+import 
org.apache.shardingsphere.mode.metadata.persist.version.VersionPersistService;
+import 
org.apache.shardingsphere.mode.node.path.type.database.metadata.rule.DatabaseRuleItem;
+import 
org.apache.shardingsphere.mode.node.path.type.database.metadata.rule.DatabaseRuleNodePath;
+import org.apache.shardingsphere.mode.spi.rule.RuleChangedItemType;
+import 
org.apache.shardingsphere.mode.spi.rule.RuleItemConfigurationChangedProcessor;
+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 org.mockito.Mock;
+
+import java.sql.SQLException;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(TypedSPILoader.class)
+class DatabaseRuleItemManagerTest {
+    
+    private static final String DATABASE_NAME = "foo_db";
+    
+    @Mock
+    private DatabaseRuleConfigurationManager ruleConfigManager;
+    
+    @Test
+    void assertAlterSuccess() throws SQLException {
+        MetaDataPersistFacade persistFacade = mockPersistFacade();
+        RuleConfiguration currentRuleConfig = 
mock(DatabaseRuleConfiguration.class);
+        RuleItemConfigurationChangedProcessor processor = 
mock(RuleItemConfigurationChangedProcessor.class);
+        
when(processor.findRuleConfiguration(any(ShardingSphereDatabase.class))).thenReturn(currentRuleConfig);
+        when(processor.swapRuleItemConfiguration(any(), any())).thenReturn(new 
Object());
+        when((TypedSPI) 
TypedSPILoader.getService(RuleItemConfigurationChangedProcessor.class, new 
RuleChangedItemType("ruleType", "type"))).thenReturn(processor);
+        DatabaseRuleItemManager manager = new 
DatabaseRuleItemManager(mock(MetaDataContexts.class, RETURNS_DEEP_STUBS), 
ruleConfigManager, persistFacade);
+        manager.alter(new DatabaseRuleNodePath(DATABASE_NAME, "ruleType", new 
DatabaseRuleItem("type/item")));
+        verify(ruleConfigManager).refresh(DATABASE_NAME, currentRuleConfig, 
true);
+        verify(processor).changeRuleItemConfiguration(eq("item"), 
eq(currentRuleConfig), any());
+    }
+    
+    @Test
+    void assertAlterWrapsSQLException() throws SQLException {
+        MetaDataPersistFacade persistFacade = mockPersistFacade();
+        RuleConfiguration currentRuleConfig = 
mock(DatabaseRuleConfiguration.class);
+        RuleItemConfigurationChangedProcessor processor = 
mock(RuleItemConfigurationChangedProcessor.class);
+        
when(processor.findRuleConfiguration(any(ShardingSphereDatabase.class))).thenReturn(currentRuleConfig);
+        when(processor.swapRuleItemConfiguration(any(), any())).thenReturn(new 
Object());
+        when((TypedSPI) 
TypedSPILoader.getService(RuleItemConfigurationChangedProcessor.class, new 
RuleChangedItemType("ruleType", "type"))).thenReturn(processor);
+        
doThrow(SQLException.class).when(ruleConfigManager).refresh(DATABASE_NAME, 
currentRuleConfig, true);
+        DatabaseRuleItemManager manager = new 
DatabaseRuleItemManager(mock(MetaDataContexts.class, RETURNS_DEEP_STUBS), 
ruleConfigManager, persistFacade);
+        assertThrows(SQLWrapperException.class, () -> manager.alter(new 
DatabaseRuleNodePath(DATABASE_NAME, "ruleType", new 
DatabaseRuleItem("type/item"))));
+        verify(processor).changeRuleItemConfiguration(eq("item"), 
eq(currentRuleConfig), any());
+    }
+    
+    @Test
+    void assertDropSuccess() throws SQLException {
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().containsDatabase(DATABASE_NAME)).thenReturn(true);
+        RuleConfiguration currentRuleConfig = 
mock(DatabaseRuleConfiguration.class);
+        RuleItemConfigurationChangedProcessor processor = 
mock(RuleItemConfigurationChangedProcessor.class);
+        
when(processor.findRuleConfiguration(any(ShardingSphereDatabase.class))).thenReturn(currentRuleConfig);
+        when((TypedSPI) 
TypedSPILoader.getService(RuleItemConfigurationChangedProcessor.class, new 
RuleChangedItemType("ruleType", null))).thenReturn(processor);
+        when((TypedSPI) 
TypedSPILoader.getService(DatabaseRuleConfigurationEmptyChecker.class, 
currentRuleConfig.getClass())).thenReturn(mock(DatabaseRuleConfigurationEmptyChecker.class));
+        DatabaseRuleItemManager manager = new 
DatabaseRuleItemManager(metaDataContexts, ruleConfigManager, 
mock(MetaDataPersistFacade.class));
+        manager.drop(new DatabaseRuleNodePath(DATABASE_NAME, "ruleType", 
null));
+        verify(processor).dropRuleItemConfiguration(null, currentRuleConfig);
+        verify(ruleConfigManager).refresh(DATABASE_NAME, currentRuleConfig, 
true);
+    }
+    
+    @Test
+    void assertDropWrapsSQLException() throws SQLException {
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().containsDatabase(DATABASE_NAME)).thenReturn(true);
+        RuleConfiguration currentRuleConfig = 
mock(DatabaseRuleConfiguration.class);
+        RuleItemConfigurationChangedProcessor processor = 
mock(RuleItemConfigurationChangedProcessor.class);
+        
when(processor.findRuleConfiguration(any(ShardingSphereDatabase.class))).thenReturn(currentRuleConfig);
+        when((TypedSPI) 
TypedSPILoader.getService(RuleItemConfigurationChangedProcessor.class, new 
RuleChangedItemType("ruleType", "type"))).thenReturn(processor);
+        when((TypedSPI) 
TypedSPILoader.getService(DatabaseRuleConfigurationEmptyChecker.class, 
currentRuleConfig.getClass())).thenReturn(mock(DatabaseRuleConfigurationEmptyChecker.class));
+        doThrow(new 
SQLException("drop")).when(ruleConfigManager).refresh(DATABASE_NAME, 
currentRuleConfig, true);
+        DatabaseRuleItemManager manager = new 
DatabaseRuleItemManager(metaDataContexts, ruleConfigManager, 
mock(MetaDataPersistFacade.class));
+        assertThrows(SQLWrapperException.class, () -> manager.drop(new 
DatabaseRuleNodePath(DATABASE_NAME, "ruleType", new 
DatabaseRuleItem("type/item"))));
+        verify(processor).dropRuleItemConfiguration("item", currentRuleConfig);
+    }
+    
+    private MetaDataPersistFacade mockPersistFacade() {
+        MetaDataPersistFacade result = mock(MetaDataPersistFacade.class);
+        VersionPersistService versionService = 
mock(VersionPersistService.class);
+        when(versionService.loadContent(any())).thenReturn("yaml-content");
+        when(result.getVersionService()).thenReturn(versionService);
+        return result;
+    }
+}
diff --git 
a/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/GlobalConfigurationManagerTest.java
 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/GlobalConfigurationManagerTest.java
new file mode 100644
index 00000000000..bbe2a321b6f
--- /dev/null
+++ 
b/mode/core/src/test/java/org/apache/shardingsphere/mode/metadata/manager/rule/GlobalConfigurationManagerTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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.mode.metadata.manager.rule;
+
+import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import 
org.apache.shardingsphere.infra.config.props.temporary.TemporaryConfigurationProperties;
+import 
org.apache.shardingsphere.infra.config.props.temporary.TemporaryConfigurationPropertyKey;
+import org.apache.shardingsphere.infra.config.rule.RuleConfiguration;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
+import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
+import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder;
+import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
+import org.apache.shardingsphere.infra.util.props.PropertiesBuilder;
+import org.apache.shardingsphere.infra.util.props.PropertiesBuilder.Property;
+import 
org.apache.shardingsphere.mode.manager.listener.StatisticsCollectJobCronUpdateListener;
+import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistFacade;
+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.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Properties;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings({ShardingSphereServiceLoader.class, 
GlobalRulesBuilder.class})
+class GlobalConfigurationManagerTest {
+    
+    @Test
+    void assertAlterGlobalRuleConfigurationWithNullValue() {
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class);
+        GlobalConfigurationManager manager = new 
GlobalConfigurationManager(metaDataContexts, mock(MetaDataPersistFacade.class));
+        manager.alterGlobalRuleConfiguration(null);
+        verify(metaDataContexts, 
never()).update(any(ShardingSphereMetaData.class), 
any(MetaDataPersistFacade.class));
+    }
+    
+    @Test
+    void assertAlterGlobalRuleConfigurationReplacesRules() {
+        RuleConfiguration newConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule closableRule = mock(ShardingSphereRule.class, 
withSettings().extraInterfaces(AutoCloseable.class));
+        
when(closableRule.getConfiguration()).thenReturn(mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class)));
+        ShardingSphereRule remainedRule = mock(ShardingSphereRule.class);
+        
when(remainedRule.getConfiguration()).thenReturn(mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Cloneable.class)));
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class);
+        when(metaDataContexts.getMetaData()).thenReturn(
+                createMetaData(new RuleMetaData(new 
LinkedList<>(Arrays.asList(closableRule, remainedRule))), new 
TemporaryConfigurationProperties(new Properties())));
+        ShardingSphereRule builtRule = mock(ShardingSphereRule.class);
+        when(GlobalRulesBuilder.buildSingleRules(eq(newConfig), any(), 
any(ConfigurationProperties.class))).thenReturn(Collections.singleton(builtRule));
+        GlobalConfigurationManager manager = new 
GlobalConfigurationManager(metaDataContexts, mock(MetaDataPersistFacade.class));
+        assertDoesNotThrow(() -> 
manager.alterGlobalRuleConfiguration(newConfig));
+        assertDoesNotThrow(() -> verify((AutoCloseable) closableRule).close());
+        Collection<ShardingSphereRule> rules = 
metaDataContexts.getMetaData().getGlobalRuleMetaData().getRules();
+        verify(metaDataContexts).update(any(ShardingSphereMetaData.class), 
any(MetaDataPersistFacade.class));
+        assertTrue(rules.contains(builtRule));
+        assertTrue(rules.contains(remainedRule));
+    }
+    
+    @Test
+    void assertAlterGlobalRuleConfigurationRemovesNonClosableAssignableRule() {
+        RuleConfiguration newConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule nonClosableAssignableRule = 
mock(ShardingSphereRule.class);
+        
when(nonClosableAssignableRule.getConfiguration()).thenReturn(mock(RuleConfiguration.class,
 withSettings().extraInterfaces(Serializable.class)));
+        ShardingSphereMetaData metaData = createMetaData(new RuleMetaData(new 
LinkedList<>(Collections.singleton(nonClosableAssignableRule))), new 
TemporaryConfigurationProperties(new Properties()));
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        when(metaDataContexts.getMetaData()).thenReturn(metaData);
+        ShardingSphereRule builtRule = mock(ShardingSphereRule.class);
+        when(GlobalRulesBuilder.buildSingleRules(eq(newConfig), any(), 
any(ConfigurationProperties.class))).thenReturn(Collections.singleton(builtRule));
+        new GlobalConfigurationManager(metaDataContexts, 
mock(MetaDataPersistFacade.class)).alterGlobalRuleConfiguration(newConfig);
+        
org.junit.jupiter.api.Assertions.assertFalse(metaDataContexts.getMetaData().getGlobalRuleMetaData().getRules().contains(nonClosableAssignableRule));
+        
assertTrue(metaDataContexts.getMetaData().getGlobalRuleMetaData().getRules().contains(builtRule));
+    }
+    
+    @Test
+    void assertAlterGlobalRuleConfigurationThrowsWhenCloseFailed() throws 
Exception {
+        RuleConfiguration newConfig = mock(RuleConfiguration.class, 
withSettings().extraInterfaces(Serializable.class));
+        ShardingSphereRule closableRule = mock(ShardingSphereRule.class, 
withSettings().extraInterfaces(AutoCloseable.class));
+        when(closableRule.getConfiguration()).thenReturn(newConfig);
+        doThrow(Exception.class).when((AutoCloseable) closableRule).close();
+        RuleMetaData globalRuleMetaData = new RuleMetaData(new 
LinkedList<>(Collections.singleton(closableRule)));
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData()).thenReturn(createMetaData(globalRuleMetaData,
 new TemporaryConfigurationProperties(new Properties())));
+        when(GlobalRulesBuilder.buildSingleRules(eq(newConfig), any(), 
any(ConfigurationProperties.class))).thenReturn(Collections.emptyList());
+        assertThrows(Exception.class, () -> new 
GlobalConfigurationManager(metaDataContexts, 
mock(MetaDataPersistFacade.class)).alterGlobalRuleConfiguration(newConfig));
+    }
+    
+    @Test
+    void assertAlterPropertiesWithCronChanged() {
+        ShardingSphereMetaData metaData = createMetaData(new 
RuleMetaData(Collections.emptyList()),
+                new 
TemporaryConfigurationProperties(PropertiesBuilder.build(new 
Property(TemporaryConfigurationPropertyKey.PROXY_META_DATA_COLLECTOR_CRON.getKey(),
 "0/10 * * * * ?"))));
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        when(metaDataContexts.getMetaData()).thenReturn(metaData);
+        StatisticsCollectJobCronUpdateListener listener = 
mock(StatisticsCollectJobCronUpdateListener.class);
+        
when(ShardingSphereServiceLoader.getServiceInstances(StatisticsCollectJobCronUpdateListener.class)).thenReturn(Collections.singleton(listener));
+        GlobalConfigurationManager manager = new 
GlobalConfigurationManager(metaDataContexts, mock(MetaDataPersistFacade.class));
+        manager.alterProperties(PropertiesBuilder.build(new 
Property(TemporaryConfigurationPropertyKey.PROXY_META_DATA_COLLECTOR_CRON.getKey(),
 "0/20 * * * * ?")));
+        verify(metaDataContexts).update(any(ShardingSphereMetaData.class), 
any(MetaDataPersistFacade.class));
+        verify(listener).updated();
+    }
+    
+    @Test
+    void assertAlterPropertiesWithoutCronChange() {
+        MetaDataContexts metaDataContexts = mock(MetaDataContexts.class, 
RETURNS_DEEP_STUBS);
+        
when(metaDataContexts.getMetaData().getTemporaryProps().getValue(TemporaryConfigurationPropertyKey.PROXY_META_DATA_COLLECTOR_CRON)).thenReturn("0/10
 * * * * ?");
+        
when(metaDataContexts.getMetaData().getAllDatabases()).thenReturn(Collections.emptyList());
+        
when(metaDataContexts.getMetaData().getGlobalRuleMetaData()).thenReturn(new 
RuleMetaData(Collections.emptyList()));
+        when(metaDataContexts.getMetaData().getProps()).thenReturn(new 
ConfigurationProperties(new Properties()));
+        GlobalConfigurationManager manager = new 
GlobalConfigurationManager(metaDataContexts, mock(MetaDataPersistFacade.class));
+        manager.alterProperties(PropertiesBuilder.build(new 
Property(TemporaryConfigurationPropertyKey.PROXY_META_DATA_COLLECTOR_CRON.getKey(),
 "0/10 * * * * ?")));
+        verify(metaDataContexts).update(any(ShardingSphereMetaData.class), 
any(MetaDataPersistFacade.class));
+    }
+    
+    private ShardingSphereMetaData createMetaData(final RuleMetaData 
globalRuleMetaData, final TemporaryConfigurationProperties temporaryProps) {
+        ShardingSphereMetaData result = new 
ShardingSphereMetaData(Collections.emptyList(), mock(ResourceMetaData.class), 
globalRuleMetaData, new ConfigurationProperties(new Properties()));
+        
result.getTemporaryProps().getProps().putAll(temporaryProps.getProps());
+        return result;
+    }
+}
diff --git 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/sql/SQLCases.java
 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/sql/SQLCases.java
index 31d558110fb..e2c59549eee 100644
--- 
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/sql/SQLCases.java
+++ 
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/sql/SQLCases.java
@@ -76,7 +76,8 @@ public final class SQLCases {
     }
     
     private Collection<String> getAllDatabaseTypes() {
-        return Arrays.asList("H2", "MySQL", "PostgreSQL", "Oracle", 
"SQLServer", "SQL92", "openGauss", "Doris", "Firebird");
+        // TODO "Presto" need to be fixed
+        return Arrays.asList("H2", "MySQL", "PostgreSQL", "Oracle", 
"SQLServer", "openGauss", "Doris", "Firebird", "ClickHouse", "SQL92");
     }
     
     private boolean containsSQLCaseType(final SQLCase sqlCase, final 
SQLCaseType caseType) {
diff --git 
a/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
 
b/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/clickhouse/InternalClickHouseParserIT.java
similarity index 79%
copy from 
test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
copy to 
test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/clickhouse/InternalClickHouseParserIT.java
index 641b221dab2..3a3f92b8122 100644
--- 
a/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
+++ 
b/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/clickhouse/InternalClickHouseParserIT.java
@@ -15,13 +15,11 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.test.it.sql.parser.presto;
+package org.apache.shardingsphere.test.it.sql.parser.clickhouse;
 
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.InternalSQLParserIT;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.InternalSQLParserITSettings;
-import org.junit.jupiter.api.Disabled;
 
-@Disabled("Presto dependency has been excluded")
-@InternalSQLParserITSettings("Presto")
-class InternalPrestoParserIT extends InternalSQLParserIT {
+@InternalSQLParserITSettings("ClickHouse")
+class InternalClickHouseParserIT extends InternalSQLParserIT {
 }
diff --git 
a/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
 
b/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
index 641b221dab2..3438ba3b890 100644
--- 
a/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
+++ 
b/test/it/parser/src/test/java/org/apache/shardingsphere/test/it/sql/parser/presto/InternalPrestoParserIT.java
@@ -19,9 +19,7 @@ package org.apache.shardingsphere.test.it.sql.parser.presto;
 
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.InternalSQLParserIT;
 import 
org.apache.shardingsphere.test.it.sql.parser.internal.InternalSQLParserITSettings;
-import org.junit.jupiter.api.Disabled;
 
-@Disabled("Presto dependency has been excluded")
 @InternalSQLParserITSettings("Presto")
 class InternalPrestoParserIT extends InternalSQLParserIT {
 }


Reply via email to