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 {
}