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 08e11717b82 Add more test cases on Shadow DistSQL (#38247)
08e11717b82 is described below

commit 08e11717b824b233da5b354f39e0184f9974df20
Author: Liang Zhang <[email protected]>
AuthorDate: Fri Feb 27 19:08:06 2026 +0800

    Add more test cases on Shadow DistSQL (#38247)
    
    * Add more test cases on Shadow DistSQL
    
    * Add more test cases on Shadow DistSQL
    
    * Add more test cases on Shadow DistSQL
    
    * Add more test cases on Shadow DistSQL
    
    * Add more test cases on Shadow DistSQL
    
    * Add more test cases on Shadow DistSQL
    
    * Add more test cases on Shadow DistSQL
---
 .../ShadowRuleStatementSupporterTest.java          | 129 +++++++++++++++
 .../AlterDefaultShadowAlgorithmExecutorTest.java   |  35 +++-
 .../update/AlterShadowRuleExecutorTest.java        | 161 ++++++++++---------
 .../CreateDefaultShadowAlgorithmExecutorTest.java  |  91 ++++++++---
 .../update/CreateShadowRuleExecutorTest.java       | 176 +++++++++++----------
 .../DropDefaultShadowAlgorithmExecutorTest.java    |  13 +-
 .../update/DropShadowAlgorithmExecutorTest.java    | 126 ++++++++++++---
 .../handler/update/DropShadowRuleExecutorTest.java | 160 ++++++++++++-------
 .../handler/update/UnusedAlgorithmFinderTest.java  |  65 ++++++++
 9 files changed, 690 insertions(+), 266 deletions(-)

diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/supporter/ShadowRuleStatementSupporterTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/supporter/ShadowRuleStatementSupporterTest.java
new file mode 100644
index 00000000000..cc8ecf3eaff
--- /dev/null
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/supporter/ShadowRuleStatementSupporterTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.shadow.distsql.handler.supporter;
+
+import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
+import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
+import org.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
+import 
org.apache.shardingsphere.shadow.config.datasource.ShadowDataSourceConfiguration;
+import org.apache.shardingsphere.shadow.config.table.ShadowTableConfiguration;
+import org.apache.shardingsphere.shadow.distsql.segment.ShadowAlgorithmSegment;
+import org.apache.shardingsphere.shadow.distsql.segment.ShadowRuleSegment;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+class ShadowRuleStatementSupporterTest {
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("getRuleNamesByConfigurationArguments")
+    void assertGetRuleNamesByConfiguration(final String name, final 
ShadowRuleConfiguration ruleConfig, final List<String> expected) {
+        assertThat(ShadowRuleStatementSupporter.getRuleNames(ruleConfig), 
is(expected));
+    }
+    
+    @Test
+    void assertGetRuleNamesBySegmentsWhenEmpty() {
+        
assertThat(ShadowRuleStatementSupporter.getRuleNames(Collections.emptyList()), 
is(Collections.emptyList()));
+    }
+    
+    @Test
+    void assertGetRuleNamesBySegmentsWhenPresent() {
+        Collection<ShadowRuleSegment> segments = Arrays.asList(
+                new ShadowRuleSegment("ds_0", "source_0", "shadow_0", 
Collections.emptyMap()), new ShadowRuleSegment("ds_1", "source_1", "shadow_1", 
Collections.emptyMap()));
+        assertThat(ShadowRuleStatementSupporter.getRuleNames(segments), 
is(Arrays.asList("ds_0", "ds_1")));
+    }
+    
+    @Test
+    void assertGetStorageUnitNamesWhenEmpty() {
+        
assertThat(ShadowRuleStatementSupporter.getStorageUnitNames(Collections.emptyList()),
 is(Collections.emptyList()));
+    }
+    
+    @Test
+    void assertGetStorageUnitNamesWhenPresent() {
+        Collection<ShadowRuleSegment> segments = Arrays.asList(
+                new ShadowRuleSegment("ds_0", "source_0", "shadow_0", 
Collections.emptyMap()), new ShadowRuleSegment("ds_1", null, "shadow_1", 
Collections.emptyMap()));
+        assertThat(ShadowRuleStatementSupporter.getStorageUnitNames(segments), 
is(Arrays.asList("source_0", "shadow_0", "shadow_1")));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("getAlgorithmNamesByConfigurationArguments")
+    void assertGetAlgorithmNamesByConfiguration(final String name, final 
ShadowRuleConfiguration ruleConfig, final List<String> expected) {
+        assertThat(ShadowRuleStatementSupporter.getAlgorithmNames(ruleConfig), 
is(expected));
+    }
+    
+    @Test
+    void assertGetAlgorithmNamesBySegmentsWhenEmpty() {
+        
assertThat(ShadowRuleStatementSupporter.getAlgorithmNames(Collections.emptyList()),
 is(Collections.emptyList()));
+    }
+    
+    @Test
+    void assertGetAlgorithmNamesBySegmentsWhenPresent() {
+        Collection<ShadowAlgorithmSegment> segments = Arrays.asList(
+                new ShadowAlgorithmSegment("algorithm_0", new 
AlgorithmSegment("SQL_HINT", new Properties())),
+                new ShadowAlgorithmSegment("algorithm_1", new 
AlgorithmSegment("SQL_HINT", new Properties())));
+        assertThat(ShadowRuleStatementSupporter.getAlgorithmNames(
+                Collections.singleton(new ShadowRuleSegment("ds_0", 
"source_0", "shadow_0", Collections.singletonMap("t_order", segments)))), 
is(Arrays.asList("algorithm_0", "algorithm_1")));
+    }
+    
+    @Test
+    void assertMergeConfiguration() {
+        ShadowTableConfiguration existingConfig = new 
ShadowTableConfiguration(new ArrayList<>(Collections.singleton("ds_0")), new 
ArrayList<>(Collections.singleton("algorithm_0")));
+        ShadowTableConfiguration newConfig = new ShadowTableConfiguration(new 
LinkedList<>(Collections.singleton("ds_1")), new 
LinkedList<>(Collections.singleton("algorithm_1")));
+        ShadowTableConfiguration actual = 
ShadowRuleStatementSupporter.mergeConfiguration(existingConfig, newConfig);
+        assertThat(actual.getDataSourceNames(), is(Arrays.asList("ds_0", 
"ds_1")));
+        assertThat(actual.getShadowAlgorithmNames(), 
is(Arrays.asList("algorithm_0", "algorithm_1")));
+    }
+    
+    private static Stream<Arguments> getRuleNamesByConfigurationArguments() {
+        return Stream.of(
+                Arguments.of("null configuration", null, 
Collections.emptyList()),
+                Arguments.of("single datasource", 
createRuleConfiguration(Collections.singleton("ds_0"), 
Collections.emptyList()), Collections.singletonList("ds_0")),
+                Arguments.of("multiple datasources", 
createRuleConfiguration(Arrays.asList("ds_0", "ds_1"), 
Collections.emptyList()), Arrays.asList("ds_0", "ds_1")));
+    }
+    
+    private static Stream<Arguments> 
getAlgorithmNamesByConfigurationArguments() {
+        return Stream.of(
+                Arguments.of("null configuration", null, 
Collections.emptyList()),
+                Arguments.of("single algorithm", 
createRuleConfiguration(Collections.emptyList(), 
Collections.singleton("algorithm_0")), 
Collections.singletonList("algorithm_0")),
+                Arguments.of("multiple algorithms", 
createRuleConfiguration(Collections.emptyList(), Arrays.asList("algorithm_0", 
"algorithm_1")), Arrays.asList("algorithm_0", "algorithm_1")));
+    }
+    
+    private static ShadowRuleConfiguration createRuleConfiguration(final 
Collection<String> dataSourceNames, final Collection<String> algorithmNames) {
+        ShadowRuleConfiguration result = new ShadowRuleConfiguration();
+        for (String each : dataSourceNames) {
+            result.getDataSources().add(new 
ShadowDataSourceConfiguration(each, each + "_source", each + "_shadow"));
+        }
+        for (String each : algorithmNames) {
+            result.getShadowAlgorithms().put(each, new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        }
+        return result;
+    }
+}
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterDefaultShadowAlgorithmExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterDefaultShadowAlgorithmExecutorTest.java
index c0f998672ae..f7602cd1870 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterDefaultShadowAlgorithmExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterDefaultShadowAlgorithmExecutorTest.java
@@ -17,12 +17,14 @@
 
 package org.apache.shardingsphere.shadow.distsql.handler.update;
 
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 import 
org.apache.shardingsphere.infra.algorithm.core.exception.MissingRequiredAlgorithmException;
 import 
org.apache.shardingsphere.infra.algorithm.core.exception.UnregisteredAlgorithmException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;
+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.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
@@ -38,6 +40,10 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import java.util.Collections;
 import java.util.Properties;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
@@ -46,7 +52,8 @@ import static org.mockito.Mockito.when;
 @ExtendWith(MockitoExtension.class)
 class AlterDefaultShadowAlgorithmExecutorTest {
     
-    private final AlterDefaultShadowAlgorithmExecutor executor = new 
AlterDefaultShadowAlgorithmExecutor();
+    private final AlterDefaultShadowAlgorithmExecutor executor = 
(AlterDefaultShadowAlgorithmExecutor) TypedSPILoader.getService(
+            DatabaseRuleDefinitionExecutor.class, 
AlterDefaultShadowAlgorithmStatement.class);
     
     @Mock
     private ShadowRuleConfiguration currentConfig;
@@ -60,8 +67,7 @@ class AlterDefaultShadowAlgorithmExecutorTest {
     void assertExecuteAlgorithmNotInMetaData() {
         Properties props = PropertiesBuilder.build(new Property("type", 
"value"));
         
when(currentConfig.getShadowAlgorithms()).thenReturn(Collections.singletonMap("sqlHintAlgorithm",
 new AlgorithmConfiguration("type", props)));
-        AlterDefaultShadowAlgorithmStatement sqlStatement = new 
AlterDefaultShadowAlgorithmStatement(
-                new ShadowAlgorithmSegment("default_shadow_algorithm", new 
AlgorithmSegment("SQL_HINT", props)));
+        AlterDefaultShadowAlgorithmStatement sqlStatement = new 
AlterDefaultShadowAlgorithmStatement(new 
ShadowAlgorithmSegment("default_shadow_algorithm", new 
AlgorithmSegment("SQL_HINT", props)));
         ShadowRule rule = mock(ShadowRule.class);
         when(rule.getConfiguration()).thenReturn(currentConfig);
         executor.setRule(rule);
@@ -89,7 +95,28 @@ class AlterDefaultShadowAlgorithmExecutorTest {
         ShadowRule rule = mock(ShadowRule.class);
         when(rule.getConfiguration()).thenReturn(currentConfig);
         executor.setRule(rule);
+        assertDoesNotThrow(() -> executor.checkBeforeUpdate(
+                new AlterDefaultShadowAlgorithmStatement(new 
ShadowAlgorithmSegment("default_shadow_algorithm", new 
AlgorithmSegment("SQL_HINT", props)))));
+    }
+    
+    @Test
+    void assertBuildToBeAlteredRuleConfiguration() {
+        Properties props = PropertiesBuilder.build(new Property("foo", "bar"));
         AlterDefaultShadowAlgorithmStatement sqlStatement = new 
AlterDefaultShadowAlgorithmStatement(new 
ShadowAlgorithmSegment("default_shadow_algorithm", new 
AlgorithmSegment("SQL_HINT", props)));
-        executor.checkBeforeUpdate(sqlStatement);
+        ShadowRuleConfiguration actual = 
executor.buildToBeAlteredRuleConfiguration(sqlStatement);
+        assertThat(actual.getDefaultShadowAlgorithmName(), 
is("default_shadow_algorithm"));
+        assertThat(actual.getShadowAlgorithms().size(), is(1));
+        
assertThat(actual.getShadowAlgorithms().get("default_shadow_algorithm").getType(),
 is("SQL_HINT"));
+        
assertThat(actual.getShadowAlgorithms().get("default_shadow_algorithm").getProps(),
 is(props));
+    }
+    
+    @Test
+    void assertBuildToBeDroppedRuleConfiguration() {
+        assertNull(executor.buildToBeDroppedRuleConfiguration(new 
ShadowRuleConfiguration()));
+    }
+    
+    @Test
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
     }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterShadowRuleExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterShadowRuleExecutorTest.java
index c8f081f164b..ca06f074d80 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterShadowRuleExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/AlterShadowRuleExecutorTest.java
@@ -17,17 +17,22 @@
 
 package org.apache.shardingsphere.shadow.distsql.handler.update;
 
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
+import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 import 
org.apache.shardingsphere.infra.algorithm.core.exception.InUsedAlgorithmException;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.MissingRequiredStorageUnitsException;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.DuplicateRuleException;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
+import 
org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;
+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.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
 import 
org.apache.shardingsphere.shadow.config.datasource.ShadowDataSourceConfiguration;
+import org.apache.shardingsphere.shadow.config.table.ShadowTableConfiguration;
 import org.apache.shardingsphere.shadow.distsql.segment.ShadowAlgorithmSegment;
 import org.apache.shardingsphere.shadow.distsql.segment.ShadowRuleSegment;
 import 
org.apache.shardingsphere.shadow.distsql.statement.AlterShadowRuleStatement;
@@ -35,21 +40,30 @@ import org.apache.shardingsphere.shadow.rule.ShadowRule;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Properties;
+import java.util.stream.Stream;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+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.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -57,7 +71,10 @@ import static org.mockito.Mockito.when;
 @MockitoSettings(strictness = Strictness.LENIENT)
 class AlterShadowRuleExecutorTest {
     
-    private final AlterShadowRuleExecutor executor = new 
AlterShadowRuleExecutor();
+    private final AlterShadowRuleExecutor executor = (AlterShadowRuleExecutor) 
TypedSPILoader.getService(DatabaseRuleDefinitionExecutor.class, 
AlterShadowRuleStatement.class);
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ShardingSphereDatabase database;
     
     @Mock
     private ResourceMetaData resourceMetaData;
@@ -70,98 +87,94 @@ class AlterShadowRuleExecutorTest {
         Collection<ShadowDataSourceConfiguration> shadowDataSource = new 
LinkedList<>();
         shadowDataSource.add(new 
ShadowDataSourceConfiguration("initRuleName1", "ds1", "ds_shadow1"));
         shadowDataSource.add(new 
ShadowDataSourceConfiguration("initRuleName2", "ds2", "ds_shadow2"));
-        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
         when(database.getResourceMetaData()).thenReturn(resourceMetaData);
+        when(database.getName()).thenReturn("shadow_db");
+        
when(resourceMetaData.getNotExistedDataSources(any())).thenReturn(Collections.emptyList());
         when(currentConfig.getDataSources()).thenReturn(shadowDataSource);
         executor.setDatabase(database);
+        executor.setRule(createRule(currentConfig));
     }
     
-    @Test
-    void assertExecuteWithDuplicateRuleName() {
-        ShadowRuleSegment ruleSegment = new ShadowRuleSegment("ruleName", 
null, null, null);
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Arrays.asList(ruleSegment, ruleSegment));
-        sqlStatement.buildAttributes();
-        assertThrows(DuplicateRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    private ShadowRule createRule(final ShadowRuleConfiguration ruleConfig) {
+        ShadowRule result = mock(ShadowRule.class);
+        when(result.getConfiguration()).thenReturn(ruleConfig);
+        return result;
     }
     
-    @Test
-    void assertExecuteWithRuleNameNotInMetaData() {
-        ShadowRuleSegment ruleSegment = new ShadowRuleSegment("ruleName", 
null, null, null);
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Collections.singleton(ruleSegment));
-        sqlStatement.buildAttributes();
-        assertThrows(MissingRequiredRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("checkBeforeUpdateFailureArguments")
+    void assertCheckBeforeUpdateWithInvalidInput(final String name, final 
AlterShadowRuleStatement sqlStatement,
+                                                 final List<String> 
notExistedStorageUnits, final Class<? extends Exception> expectedException) {
+        
when(resourceMetaData.getNotExistedDataSources(any())).thenReturn(notExistedStorageUnits);
+        assertThrows(expectedException, () -> 
executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
-    void assertExecuteWithNotExistResource() {
-        List<String> dataSources = Arrays.asList("ds", "ds0");
-        
when(resourceMetaData.getNotExistedDataSources(any())).thenReturn(dataSources);
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Collections.singleton(new 
ShadowRuleSegment("initRuleName1", "ds3", null, null)));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        assertThrows(MissingRequiredStorageUnitsException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertCheckBeforeUpdate() {
+        Properties props = PropertiesBuilder.build(new Property("type", 
"value"));
+        ShadowAlgorithmSegment segment1 = new 
ShadowAlgorithmSegment("algorithmName1", new AlgorithmSegment("SQL_HINT", 
props));
+        ShadowAlgorithmSegment segment2 = new 
ShadowAlgorithmSegment("algorithmName2", new AlgorithmSegment("SQL_HINT", 
props));
+        AlterShadowRuleStatement sqlStatement = 
createAlterStatement(Arrays.asList(
+                new ShadowRuleSegment("initRuleName1", "ds_0", null, 
Collections.singletonMap("t_order", Collections.singleton(segment1))),
+                new ShadowRuleSegment("initRuleName2", "ds_1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment2)))));
+        assertDoesNotThrow(() -> executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
-    void assertExecuteDuplicateAlgorithm() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("name", 
PropertiesBuilder.build(new Property("type", "value"))));
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Arrays.asList(
-                new ShadowRuleSegment("initRuleName1", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment))),
-                new ShadowRuleSegment("initRuleName2", "ds1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        assertThrows(InUsedAlgorithmException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertBuildToBeAlteredRuleConfiguration() {
+        ShadowAlgorithmSegment algorithmSegment = new 
ShadowAlgorithmSegment("algorithm_name", new AlgorithmSegment("SQL_HINT", 
PropertiesBuilder.build(new Property("type", "value"))));
+        AlterShadowRuleStatement sqlStatement = createAlterStatement(
+                Collections.singleton(new ShadowRuleSegment("initRuleName1", 
"ds_0", "ds_0_shadow", Collections.singletonMap("t_order", 
Collections.singleton(algorithmSegment)))));
+        ShadowRuleConfiguration actual = 
executor.buildToBeAlteredRuleConfiguration(sqlStatement);
+        assertThat(actual.getDataSources().size(), is(1));
+        assertThat(actual.getShadowAlgorithms().size(), is(1));
+        assertThat(actual.getTables().size(), is(1));
     }
     
     @Test
-    void assertExecuteDuplicateAlgorithmWithoutConfiguration() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("name", 
PropertiesBuilder.build(new Property("type", "value"))));
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Arrays.asList(
-                new ShadowRuleSegment("initRuleName1", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment))),
-                new ShadowRuleSegment("initRuleName2", "ds1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        assertThrows(InUsedAlgorithmException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertBuildToBeDroppedRuleConfiguration() {
+        ShadowRuleConfiguration ruleConfig = new ShadowRuleConfiguration();
+        ruleConfig.getShadowAlgorithms().put("used_algorithm", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        ruleConfig.getShadowAlgorithms().put("unused_algorithm", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        ruleConfig.getTables().put("t_order", new ShadowTableConfiguration(new 
ArrayList<>(Collections.singleton("initRuleName1")), new 
ArrayList<>(Collections.singleton("used_algorithm"))));
+        ruleConfig.setDefaultShadowAlgorithmName("used_algorithm");
+        executor.setRule(createRule(ruleConfig));
+        ShadowRuleConfiguration actual = 
executor.buildToBeDroppedRuleConfiguration(new ShadowRuleConfiguration());
+        assertThat(actual.getShadowAlgorithms().size(), is(1));
+        
assertTrue(actual.getShadowAlgorithms().containsKey("unused_algorithm"));
     }
     
     @Test
-    void assertExecuteSuccess() {
-        Properties props = PropertiesBuilder.build(new Property("type", 
"value"));
-        ShadowAlgorithmSegment segment1 = new 
ShadowAlgorithmSegment("algorithmName1", new AlgorithmSegment("SQL_HINT", 
props));
-        ShadowAlgorithmSegment segment2 = new 
ShadowAlgorithmSegment("algorithmName2", new AlgorithmSegment("SQL_HINT", 
props));
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Arrays.asList(
-                new ShadowRuleSegment("initRuleName1", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment1))),
-                new ShadowRuleSegment("initRuleName2", "ds1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment2)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
     }
     
-    @Test
-    void assertExecuteSuccessWithoutProps() {
-        ShadowAlgorithmSegment segment1 = new 
ShadowAlgorithmSegment("algorithmName1", new AlgorithmSegment("SQL_HINT", 
null));
-        ShadowAlgorithmSegment segment2 = new 
ShadowAlgorithmSegment("algorithmName2", new AlgorithmSegment("SQL_HINT", 
null));
-        AlterShadowRuleStatement sqlStatement = new 
AlterShadowRuleStatement(Arrays.asList(
-                new ShadowRuleSegment("initRuleName1", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment1))),
-                new ShadowRuleSegment("initRuleName2", "ds1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment2)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
+    private static Stream<Arguments> checkBeforeUpdateFailureArguments() {
+        ShadowAlgorithmSegment duplicatedAlgorithmSegment = new 
ShadowAlgorithmSegment("duplicated_algorithm",
+                new AlgorithmSegment("SQL_HINT", PropertiesBuilder.build(new 
Property("type", "value"))));
+        ShadowAlgorithmSegment invalidTypeSegment = new 
ShadowAlgorithmSegment("invalid_type_algorithm",
+                new AlgorithmSegment("INVALID_TYPE", 
PropertiesBuilder.build(new Property("type", "value"))));
+        return Stream.of(
+                Arguments.of("duplicate rule name", 
createAlterStatement(Arrays.asList(
+                        new ShadowRuleSegment("rule_name", null, null, null),
+                        new ShadowRuleSegment("rule_name", null, null, 
null))), Collections.emptyList(), DuplicateRuleException.class),
+                Arguments.of("rule not found", 
createAlterStatement(Collections.singleton(
+                        new ShadowRuleSegment("missing_rule", null, null, 
null))), Collections.emptyList(), MissingRequiredRuleException.class),
+                Arguments.of("storage unit not found", 
createAlterStatement(Collections.singleton(
+                        new ShadowRuleSegment("initRuleName1", 
"missing_storage_unit", null, null))), 
Collections.singletonList("missing_storage_unit"),
+                        MissingRequiredStorageUnitsException.class),
+                Arguments.of("duplicate algorithm name", 
createAlterStatement(Arrays.asList(
+                        new ShadowRuleSegment("initRuleName1", "ds_0", null, 
Collections.singletonMap("t_order", 
Collections.singleton(duplicatedAlgorithmSegment))),
+                        new ShadowRuleSegment("initRuleName2", "ds_1", null, 
Collections.singletonMap("t_order_1", 
Collections.singleton(duplicatedAlgorithmSegment))))),
+                        Collections.emptyList(), 
InUsedAlgorithmException.class),
+                Arguments.of("invalid algorithm type", 
createAlterStatement(Collections.singleton(
+                        new ShadowRuleSegment("initRuleName1", "ds_0", null, 
Collections.singletonMap("t_order", 
Collections.singleton(invalidTypeSegment))))),
+                        Collections.emptyList(), 
ServiceProviderNotFoundException.class));
+    }
+    
+    private static AlterShadowRuleStatement createAlterStatement(final 
Collection<ShadowRuleSegment> rules) {
+        AlterShadowRuleStatement result = new AlterShadowRuleStatement(rules);
+        result.buildAttributes();
+        return result;
     }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateDefaultShadowAlgorithmExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateDefaultShadowAlgorithmExecutorTest.java
index 3b70e9bf25f..396b0c400d5 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateDefaultShadowAlgorithmExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateDefaultShadowAlgorithmExecutorTest.java
@@ -17,57 +17,112 @@
 
 package org.apache.shardingsphere.shadow.distsql.handler.update;
 
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
+import 
org.apache.shardingsphere.infra.algorithm.core.exception.InUsedAlgorithmException;
+import 
org.apache.shardingsphere.infra.algorithm.core.exception.MissingRequiredAlgorithmException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;
+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.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
 import org.apache.shardingsphere.shadow.distsql.segment.ShadowAlgorithmSegment;
 import 
org.apache.shardingsphere.shadow.distsql.statement.CreateDefaultShadowAlgorithmStatement;
 import org.apache.shardingsphere.shadow.rule.ShadowRule;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Answers;
+import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
 
+import java.util.stream.Stream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
 class CreateDefaultShadowAlgorithmExecutorTest {
     
-    private final CreateDefaultShadowAlgorithmExecutor executor = new 
CreateDefaultShadowAlgorithmExecutor();
+    private final CreateDefaultShadowAlgorithmExecutor executor = 
(CreateDefaultShadowAlgorithmExecutor) TypedSPILoader.getService(
+            DatabaseRuleDefinitionExecutor.class, 
CreateDefaultShadowAlgorithmStatement.class);
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ShardingSphereDatabase database;
     
     @BeforeEach
     void setUp() {
-        executor.setDatabase(mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS));
+        when(database.getName()).thenReturn("shadow_db");
+        executor.setDatabase(database);
     }
     
-    @Test
-    void assertExecuteWithInvalidAlgorithm() {
-        CreateDefaultShadowAlgorithmStatement statement = 
mock(CreateDefaultShadowAlgorithmStatement.class);
-        when(statement.getShadowAlgorithmSegment()).thenReturn(new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("name", 
PropertiesBuilder.build(new Property("type", "value")))));
-        ShadowRule rule = mock(ShadowRule.class);
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("checkBeforeUpdateFailureArguments")
+    void assertCheckBeforeUpdateWithInvalidInput(final String name, final 
CreateDefaultShadowAlgorithmStatement sqlStatement,
+                                                 final ShadowRule rule, final 
Class<? extends Exception> expectedException) {
         executor.setRule(rule);
-        assertThrows(ServiceProviderNotFoundException.class, () -> 
executor.checkBeforeUpdate(statement));
+        assertThrows(expectedException, () -> 
executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
-    void assertExecuteSuccess() {
-        CreateDefaultShadowAlgorithmStatement sqlStatement = 
mock(CreateDefaultShadowAlgorithmStatement.class);
-        when(sqlStatement.getShadowAlgorithmSegment()).thenReturn(
-                new ShadowAlgorithmSegment("algorithmName", new 
AlgorithmSegment("SQL_HINT", PropertiesBuilder.build(new Property("type", 
"value")))));
+    void assertCheckBeforeUpdate() {
+        executor.setRule(null);
+        assertDoesNotThrow(() -> 
executor.checkBeforeUpdate(createStatement(false, "SQL_HINT")));
+    }
+    
+    @Test
+    void assertCheckBeforeUpdateWithIfNotExists() {
         ShadowRule rule = mock(ShadowRule.class);
         executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
+        assertDoesNotThrow(() -> 
executor.checkBeforeUpdate(createStatement(true, "SQL_HINT")));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("buildToBeCreatedRuleConfigurationArguments")
+    void assertBuildToBeCreatedRuleConfiguration(final String name, final 
ShadowRule rule, final int expectedAlgorithmSize, final String 
expectedDefaultAlgorithmName) {
+        executor.setRule(rule);
+        ShadowRuleConfiguration actual = 
executor.buildToBeCreatedRuleConfiguration(createStatement(false, "SQL_HINT"));
+        assertThat(actual.getShadowAlgorithms().size(), 
is(expectedAlgorithmSize));
+        
assertThat(actual.getShadowAlgorithms().containsKey("default_shadow_algorithm"),
 is(expectedAlgorithmSize > 0));
+        assertThat(actual.getDefaultShadowAlgorithmName(), 
is(expectedDefaultAlgorithmName));
     }
     
     @Test
-    void assertExecuteWithIfNotExists() {
-        ShadowAlgorithmSegment shadowAlgorithmSegment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("SQL_HINT", 
PropertiesBuilder.build(new Property("type", "value"))));
-        CreateDefaultShadowAlgorithmStatement sqlStatement = new 
CreateDefaultShadowAlgorithmStatement(true, shadowAlgorithmSegment);
-        executor.checkBeforeUpdate(sqlStatement);
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
+    }
+    
+    private static Stream<Arguments> checkBeforeUpdateFailureArguments() {
+        ShadowRule duplicatedRule = mock(ShadowRule.class);
+        
when(duplicatedRule.containsShadowAlgorithm("default_shadow_algorithm")).thenReturn(true);
+        return Stream.of(
+                Arguments.of("missing algorithm type", createStatement(false, 
""), null, MissingRequiredAlgorithmException.class),
+                Arguments.of("invalid algorithm type", createStatement(false, 
"INVALID_TYPE"), null, ServiceProviderNotFoundException.class),
+                Arguments.of("duplicate default algorithm", 
createStatement(false, "SQL_HINT"), duplicatedRule, 
InUsedAlgorithmException.class));
+    }
+    
+    private static CreateDefaultShadowAlgorithmStatement createStatement(final 
boolean ifNotExists, final String algorithmType) {
+        ShadowAlgorithmSegment shadowAlgorithmSegment = new 
ShadowAlgorithmSegment("algorithm_name", new AlgorithmSegment(algorithmType, 
PropertiesBuilder.build(new Property("type", "value"))));
+        return new CreateDefaultShadowAlgorithmStatement(ifNotExists, 
shadowAlgorithmSegment);
+    }
+    
+    private static Stream<Arguments> 
buildToBeCreatedRuleConfigurationArguments() {
+        ShadowRule duplicatedRule = mock(ShadowRule.class);
+        
when(duplicatedRule.containsShadowAlgorithm("default_shadow_algorithm")).thenReturn(true);
+        return Stream.of(
+                Arguments.of("rule is null", null, 1, 
"default_shadow_algorithm"),
+                Arguments.of("rule without default algorithm", 
mock(ShadowRule.class), 1, "default_shadow_algorithm"),
+                Arguments.of("rule already has default algorithm", 
duplicatedRule, 0, null));
     }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateShadowRuleExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateShadowRuleExecutorTest.java
index 073d36f03db..e6c28c347b3 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateShadowRuleExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/CreateShadowRuleExecutorTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.shadow.distsql.handler.update;
 
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.MissingRequiredStorageUnitsException;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.DuplicateRuleException;
@@ -25,6 +26,7 @@ import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
 import 
org.apache.shardingsphere.infra.rule.attribute.datasource.DataSourceMapperRuleAttribute;
 import 
org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;
+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.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
@@ -36,6 +38,9 @@ import org.apache.shardingsphere.shadow.rule.ShadowRule;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
@@ -43,11 +48,17 @@ import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
+import java.util.stream.Stream;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+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.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -55,7 +66,7 @@ import static org.mockito.Mockito.when;
 @MockitoSettings(strictness = Strictness.LENIENT)
 class CreateShadowRuleExecutorTest {
     
-    private final CreateShadowRuleExecutor executor = new 
CreateShadowRuleExecutor();
+    private final CreateShadowRuleExecutor executor = 
(CreateShadowRuleExecutor) 
TypedSPILoader.getService(DatabaseRuleDefinitionExecutor.class, 
CreateShadowRuleStatement.class);
     
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private ShardingSphereDatabase database;
@@ -63,116 +74,109 @@ class CreateShadowRuleExecutorTest {
     @Mock
     private ResourceMetaData resourceMetaData;
     
-    @Mock
-    private ShadowRuleConfiguration currentConfig;
-    
     @BeforeEach
     void setUp() {
+        
when(resourceMetaData.getNotExistedDataSources(any())).thenReturn(Collections.emptyList());
         when(database.getResourceMetaData()).thenReturn(resourceMetaData);
+        
when(database.getRuleMetaData().getAttributes(DataSourceMapperRuleAttribute.class)).thenReturn(Collections.emptyList());
         when(database.getName()).thenReturn("shadow_db");
-        
when(currentConfig.getDataSources()).thenReturn(Collections.singleton(new 
ShadowDataSourceConfiguration("initRuleName", "initDs0", "initDs0Shadow")));
         executor.setDatabase(database);
+        executor.setRule(createRule(createCurrentRuleConfiguration()));
     }
     
-    @Test
-    void assertExecuteWithDuplicateRuleName() {
-        ShadowRuleSegment ruleSegment = new ShadowRuleSegment("ruleName", 
null, null, null);
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false, Arrays.asList(ruleSegment, ruleSegment));
-        sqlStatement.buildAttributes();
-        assertThrows(DuplicateRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("checkBeforeUpdateFailureArguments")
+    void assertCheckBeforeUpdateWithInvalidInput(final String name, final 
CreateShadowRuleStatement sqlStatement, final ShadowRule rule,
+                                                 final Collection<String> 
notExistedStorageUnits, final Collection<DataSourceMapperRuleAttribute> 
ruleAttributes,
+                                                 final Class<? extends 
Exception> expectedException) {
+        
when(resourceMetaData.getNotExistedDataSources(any())).thenReturn(notExistedStorageUnits);
+        
when(database.getRuleMetaData().getAttributes(DataSourceMapperRuleAttribute.class)).thenReturn(ruleAttributes);
+        executor.setRule(rule);
+        assertThrows(expectedException, () -> 
executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
-    void assertExecuteWithDuplicateRuleNameInMetaData() {
-        
when(currentConfig.getDataSources()).thenReturn(Collections.singleton(new 
ShadowDataSourceConfiguration("ruleName", "ds", "ds_shadow")));
-        ShadowRuleSegment ruleSegment = new ShadowRuleSegment("ruleName", 
null, null, null);
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false, Collections.singleton(ruleSegment));
-        sqlStatement.buildAttributes();
-        assertThrows(DuplicateRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertCheckBeforeUpdate() {
+        assertDoesNotThrow(() -> 
executor.checkBeforeUpdate(createStatement(false, 
Collections.singleton(createShadowRuleSegment("rule_name", "ds_0", 
"algorithm_name", "SQL_HINT", "t_order")))));
     }
     
     @Test
-    void assertExecuteWithDuplicateLogicResource() {
-        DataSourceMapperRuleAttribute ruleAttribute = 
mock(DataSourceMapperRuleAttribute.class, RETURNS_DEEP_STUBS);
-        
when(ruleAttribute.getDataSourceMapper()).thenReturn(Collections.singletonMap("duplicate_ds",
 Collections.singleton("ds_0")));
-        
when(database.getRuleMetaData().getAttributes(DataSourceMapperRuleAttribute.class)).thenReturn(Collections.singleton(ruleAttribute));
-        executor.setDatabase(database);
-        ShadowRuleSegment ruleSegment = new ShadowRuleSegment("duplicate_ds", 
null, null, null);
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false, Collections.singleton(ruleSegment));
-        sqlStatement.buildAttributes();
-        assertThrows(InvalidRuleConfigurationException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertBuildToBeCreatedRuleConfiguration() {
+        ShadowRuleConfiguration actual = 
executor.buildToBeCreatedRuleConfiguration(
+                createStatement(false, 
Collections.singleton(createShadowRuleSegment("rule_name", "ds_0", 
"algorithm_name", "SQL_HINT", "t_order"))));
+        assertThat(actual.getDataSources().size(), is(1));
+        assertThat(actual.getTables().size(), is(1));
+        assertThat(actual.getShadowAlgorithms().size(), is(1));
     }
     
     @Test
-    void assertExecuteWithNotExistResource() {
-        
when(resourceMetaData.getNotExistedDataSources(any())).thenReturn(Arrays.asList("ds0",
 "ds1"));
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false, Collections.singleton(new 
ShadowRuleSegment("ruleName", "ds1", null, null)));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        assertThrows(MissingRequiredStorageUnitsException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertBuildToBeCreatedRuleConfigurationWithIfNotExists() {
+        CreateShadowRuleStatement sqlStatement = createStatement(true, 
Arrays.asList(
+                createShadowRuleSegment("initRuleName", "ds_0", 
"algorithm_name_0", "SQL_HINT", "t_order"),
+                createShadowRuleSegment("new_rule_name", "ds_1", 
"algorithm_name_1", "SQL_HINT", "t_order_1")));
+        executor.setRule(createRule(createCurrentRuleConfiguration()));
+        ShadowRuleConfiguration actual = 
executor.buildToBeCreatedRuleConfiguration(sqlStatement);
+        assertThat(actual.getDataSources().size(), is(1));
+        assertThat(actual.getDataSources().iterator().next().getName(), 
is("new_rule_name"));
+        assertTrue(actual.getTables().containsKey("t_order_1"));
+        
assertTrue(actual.getShadowAlgorithms().containsKey("algorithm_name_1"));
     }
     
     @Test
-    void assertExecuteDuplicateAlgorithm() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("name", 
PropertiesBuilder.build(new Property("type", "value"))));
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false, Arrays.asList(
-                new ShadowRuleSegment("ruleName", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment))),
-                new ShadowRuleSegment("ruleName", "ds1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        assertThrows(DuplicateRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
     }
     
-    @Test
-    void assertExecuteDuplicateAlgorithmWithoutConfiguration() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("name", 
PropertiesBuilder.build(new Property("type", "value"))));
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false, Arrays.asList(
-                new ShadowRuleSegment("ruleName", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment))),
-                new ShadowRuleSegment("ruleName1", "ds1", null, 
Collections.singletonMap("t_order_1", Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        assertThrows(DuplicateRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    private static Stream<Arguments> checkBeforeUpdateFailureArguments() {
+        DataSourceMapperRuleAttribute duplicatedLogicDataSourceAttribute = 
mock(DataSourceMapperRuleAttribute.class);
+        
when(duplicatedLogicDataSourceAttribute.getDataSourceMapper()).thenReturn(Collections.singletonMap("duplicate_ds",
 Collections.singleton("ds_0")));
+        ShadowAlgorithmSegment duplicatedAlgorithmSegment = 
createShadowAlgorithmSegment("duplicated_algorithm", "SQL_HINT");
+        return Stream.of(
+                Arguments.of("duplicate rule name", createStatement(false, 
Arrays.asList(
+                        new ShadowRuleSegment("rule_name", null, null, null),
+                        new ShadowRuleSegment("rule_name", null, null, 
null))), createRule(createCurrentRuleConfiguration()),
+                        Collections.emptyList(), Collections.emptyList(), 
DuplicateRuleException.class),
+                Arguments.of("duplicate current rule", createStatement(false, 
Collections.singleton(
+                        createShadowRuleSegment("initRuleName", "ds_0", 
"algorithm_name", "SQL_HINT", "t_order"))), 
createRule(createCurrentRuleConfiguration()),
+                        Collections.emptyList(), Collections.emptyList(), 
DuplicateRuleException.class),
+                Arguments.of("duplicate logic datasource", 
createStatement(false, Collections.singleton(
+                        createShadowRuleSegment("duplicate_ds", "ds_0", 
"algorithm_name", "SQL_HINT", "t_order"))), 
createRule(createCurrentRuleConfiguration()),
+                        Collections.emptyList(), 
Collections.singleton(duplicatedLogicDataSourceAttribute), 
InvalidRuleConfigurationException.class),
+                Arguments.of("missing storage unit", createStatement(false, 
Collections.singleton(
+                        createShadowRuleSegment("rule_name", "missing_ds", 
"algorithm_name", "SQL_HINT", "t_order"))), 
createRule(createCurrentRuleConfiguration()),
+                        Collections.singleton("missing_ds"), 
Collections.emptyList(), MissingRequiredStorageUnitsException.class),
+                Arguments.of("duplicate algorithm", createStatement(false, 
Arrays.asList(
+                        new ShadowRuleSegment("rule_name_0", "ds_0", null, 
Collections.singletonMap("t_order", 
Collections.singleton(duplicatedAlgorithmSegment))),
+                        new ShadowRuleSegment("rule_name_1", "ds_1", null, 
Collections.singletonMap("t_order_1", 
Collections.singleton(duplicatedAlgorithmSegment))))),
+                        createRule(createCurrentRuleConfiguration()), 
Collections.emptyList(), Collections.emptyList(), DuplicateRuleException.class),
+                Arguments.of("invalid algorithm type", createStatement(false, 
Collections.singleton(
+                        createShadowRuleSegment("rule_name", "ds_0", 
"algorithm_name", "INVALID_TYPE", "t_order"))), 
createRule(createCurrentRuleConfiguration()),
+                        Collections.emptyList(), Collections.emptyList(), 
ServiceProviderNotFoundException.class));
     }
     
-    @Test
-    void assertInvalidAlgorithmConfiguration() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("type", 
PropertiesBuilder.build(new Property("type", "value"))));
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false,
-                Collections.singleton(new ShadowRuleSegment("ruleName", "ds", 
null, Collections.singletonMap("t_order", Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        assertThrows(ServiceProviderNotFoundException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    private static CreateShadowRuleStatement createStatement(final boolean 
ifNotExists, final Collection<ShadowRuleSegment> rules) {
+        CreateShadowRuleStatement result = new 
CreateShadowRuleStatement(ifNotExists, new LinkedList<>(rules));
+        result.buildAttributes();
+        return result;
     }
     
-    @Test
-    void assertExecuteWithoutProps() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("SQL_HINT", null));
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(false,
-                Collections.singleton(new 
ShadowRuleSegment("initRuleNameWithoutProps", "ds", null, 
Collections.singletonMap("t_order", Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
+    private static ShadowRuleSegment createShadowRuleSegment(final String 
ruleName, final String source, final String algorithmName, final String 
algorithmType, final String tableName) {
+        return new ShadowRuleSegment(ruleName, source, null, 
Collections.singletonMap(tableName, 
Collections.singleton(createShadowAlgorithmSegment(algorithmName, 
algorithmType))));
     }
     
-    @Test
-    void assertExecuteWithIfNotExists() {
-        ShadowAlgorithmSegment segment = new 
ShadowAlgorithmSegment("algorithmName", new AlgorithmSegment("SQL_HINT", 
PropertiesBuilder.build(new Property("type", "value"))));
-        CreateShadowRuleStatement sqlStatement = new 
CreateShadowRuleStatement(true,
-                Collections.singleton(new ShadowRuleSegment("initRuleName", 
"ds", null, Collections.singletonMap("t_order", 
Collections.singleton(segment)))));
-        sqlStatement.buildAttributes();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(currentConfig);
-        executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
+    private static ShadowAlgorithmSegment createShadowAlgorithmSegment(final 
String algorithmName, final String algorithmType) {
+        return new ShadowAlgorithmSegment(algorithmName, new 
AlgorithmSegment(algorithmType, PropertiesBuilder.build(new Property("type", 
"value"))));
+    }
+    
+    private static ShadowRuleConfiguration createCurrentRuleConfiguration() {
+        ShadowRuleConfiguration result = new ShadowRuleConfiguration();
+        result.getDataSources().add(new 
ShadowDataSourceConfiguration("initRuleName", "init_ds_0", "init_ds_0_shadow"));
+        return result;
+    }
+    
+    private static ShadowRule createRule(final ShadowRuleConfiguration 
ruleConfig) {
+        ShadowRule result = mock(ShadowRule.class);
+        when(result.getConfiguration()).thenReturn(ruleConfig);
+        return result;
     }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropDefaultShadowAlgorithmExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropDefaultShadowAlgorithmExecutorTest.java
index 6d7d9176c0f..d37c73507ca 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropDefaultShadowAlgorithmExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropDefaultShadowAlgorithmExecutorTest.java
@@ -19,7 +19,9 @@ package 
org.apache.shardingsphere.shadow.distsql.handler.update;
 
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 import 
org.apache.shardingsphere.infra.algorithm.core.exception.UnregisteredAlgorithmException;
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
 import 
org.apache.shardingsphere.shadow.distsql.statement.DropDefaultShadowAlgorithmStatement;
 import org.apache.shardingsphere.shadow.rule.ShadowRule;
@@ -31,6 +33,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -40,7 +43,8 @@ import static org.mockito.Mockito.when;
 @ExtendWith(MockitoExtension.class)
 class DropDefaultShadowAlgorithmExecutorTest {
     
-    private final DropDefaultShadowAlgorithmExecutor executor = new 
DropDefaultShadowAlgorithmExecutor();
+    private final DropDefaultShadowAlgorithmExecutor executor = 
(DropDefaultShadowAlgorithmExecutor) TypedSPILoader.getService(
+            DatabaseRuleDefinitionExecutor.class, 
DropDefaultShadowAlgorithmStatement.class);
     
     @Mock
     private ShadowRuleConfiguration currentConfig;
@@ -60,7 +64,7 @@ class DropDefaultShadowAlgorithmExecutorTest {
     
     @Test
     void assertCheckWithIfExists() {
-        executor.checkBeforeUpdate(new 
DropDefaultShadowAlgorithmStatement(true));
+        assertDoesNotThrow(() -> executor.checkBeforeUpdate(new 
DropDefaultShadowAlgorithmStatement(true)));
     }
     
     @Test
@@ -78,4 +82,9 @@ class DropDefaultShadowAlgorithmExecutorTest {
         assertThat(toBeDroppedRuleConfig.getDefaultShadowAlgorithmName(), 
is("default"));
         assertThat(toBeDroppedRuleConfig.getShadowAlgorithms().size(), is(1));
     }
+    
+    @Test
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
+    }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowAlgorithmExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowAlgorithmExecutorTest.java
index 196cb706bff..c130bfddb21 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowAlgorithmExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowAlgorithmExecutorTest.java
@@ -17,58 +17,138 @@
 
 package org.apache.shardingsphere.shadow.distsql.handler.update;
 
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
+import 
org.apache.shardingsphere.infra.algorithm.core.exception.InUsedAlgorithmException;
+import 
org.apache.shardingsphere.infra.algorithm.core.exception.UnregisteredAlgorithmException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
+import org.apache.shardingsphere.shadow.config.table.ShadowTableConfiguration;
 import 
org.apache.shardingsphere.shadow.distsql.statement.DropShadowAlgorithmStatement;
 import org.apache.shardingsphere.shadow.rule.ShadowRule;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
 
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Properties;
+import java.util.stream.Stream;
 
-import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.hamcrest.Matchers.is;
+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.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
 class DropShadowAlgorithmExecutorTest {
     
-    private final DropShadowAlgorithmExecutor executor = new 
DropShadowAlgorithmExecutor();
+    private final DropShadowAlgorithmExecutor executor = 
(DropShadowAlgorithmExecutor) 
TypedSPILoader.getService(DatabaseRuleDefinitionExecutor.class, 
DropShadowAlgorithmStatement.class);
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ShardingSphereDatabase database;
     
     @BeforeEach
     void setUp() {
-        executor.setDatabase(mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS));
+        when(database.getName()).thenReturn("shadow_db");
+        executor.setDatabase(database);
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("checkBeforeUpdateFailureArguments")
+    void assertCheckBeforeUpdateWithInvalidInput(final String name, final 
ShadowRuleConfiguration ruleConfig,
+                                                 final 
DropShadowAlgorithmStatement sqlStatement, final Class<? extends Exception> 
expectedException) {
+        executor.setRule(createRule(ruleConfig));
+        assertThrows(expectedException, () -> 
executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
-    void assertExecuteWithIfExists() {
-        DropShadowAlgorithmStatement sqlStatement = createSQLStatement(true, 
"ruleSegment");
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(new 
ShadowRuleConfiguration());
-        executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
+    void assertCheckBeforeUpdate() {
+        ShadowRuleConfiguration ruleConfig = new ShadowRuleConfiguration();
+        ruleConfig.getShadowAlgorithms().put("droppable_algorithm", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        ruleConfig.getTables().put("t_order_empty", new 
ShadowTableConfiguration(new LinkedList<>(), new 
LinkedList<>(Collections.singleton("droppable_algorithm"))));
+        executor.setRule(createRule(ruleConfig));
+        assertDoesNotThrow(() -> executor.checkBeforeUpdate(new 
DropShadowAlgorithmStatement(false, 
Collections.singleton("droppable_algorithm"))));
     }
     
     @Test
-    void assertUpdate() {
+    void assertCheckBeforeUpdateWithIfExists() {
+        executor.setRule(createRule(new ShadowRuleConfiguration()));
+        assertDoesNotThrow(() -> executor.checkBeforeUpdate(new 
DropShadowAlgorithmStatement(true, 
Collections.singleton("missing_algorithm"))));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("hasAnyOneToBeDroppedArguments")
+    void assertHasAnyOneToBeDropped(final String name, final 
DropShadowAlgorithmStatement sqlStatement, final boolean expected) {
         ShadowRuleConfiguration ruleConfig = new ShadowRuleConfiguration();
-        ruleConfig.getShadowAlgorithms().put("shadow_algorithm", new 
AlgorithmConfiguration("type", null));
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(ruleConfig);
-        executor.setRule(rule);
-        DropShadowAlgorithmStatement sqlStatement = 
createSQLStatement("shadow_algorithm");
-        executor.checkBeforeUpdate(sqlStatement);
-        ShadowRuleConfiguration toBeDroppedRuleConfig = 
executor.buildToBeDroppedRuleConfiguration(sqlStatement);
-        assertThat(toBeDroppedRuleConfig.getShadowAlgorithms().size(), is(1));
+        ruleConfig.getShadowAlgorithms().put("algorithm_0", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        ruleConfig.getShadowAlgorithms().put("algorithm_1", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        executor.setRule(createRule(ruleConfig));
+        assertThat(executor.hasAnyOneToBeDropped(sqlStatement), is(expected));
+    }
+    
+    @Test
+    void assertBuildToBeDroppedRuleConfiguration() {
+        ShadowRuleConfiguration ruleConfig = new ShadowRuleConfiguration();
+        ruleConfig.getShadowAlgorithms().put("algorithm_0", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        ruleConfig.getShadowAlgorithms().put("algorithm_1", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        executor.setRule(createRule(ruleConfig));
+        DropShadowAlgorithmStatement sqlStatement = new 
DropShadowAlgorithmStatement(false, Arrays.asList("algorithm_0", 
"algorithm_1"));
+        ShadowRuleConfiguration actual = 
executor.buildToBeDroppedRuleConfiguration(sqlStatement);
+        assertThat(actual.getShadowAlgorithms().size(), is(2));
+        
assertTrue(actual.getShadowAlgorithms().keySet().containsAll(sqlStatement.getNames()));
+    }
+    
+    private ShadowRule createRule(final ShadowRuleConfiguration ruleConfig) {
+        ShadowRule result = mock(ShadowRule.class);
+        when(result.getConfiguration()).thenReturn(ruleConfig);
+        return result;
+    }
+    
+    @Test
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
     }
     
-    private DropShadowAlgorithmStatement createSQLStatement(final String... 
ruleName) {
-        return new DropShadowAlgorithmStatement(false, 
Arrays.asList(ruleName));
+    private static Stream<Arguments> checkBeforeUpdateFailureArguments() {
+        ShadowRuleConfiguration notRegisteredConfig = new 
ShadowRuleConfiguration();
+        notRegisteredConfig.getShadowAlgorithms().put("registered_algorithm", 
new AlgorithmConfiguration("SQL_HINT", new Properties()));
+        ShadowRuleConfiguration inUsedAlgorithmConfig = new 
ShadowRuleConfiguration();
+        inUsedAlgorithmConfig.getShadowAlgorithms().put("in_used_algorithm", 
new AlgorithmConfiguration("SQL_HINT", new Properties()));
+        
inUsedAlgorithmConfig.getShadowAlgorithms().put("algorithm_from_empty_table", 
new AlgorithmConfiguration("SQL_HINT", new Properties()));
+        inUsedAlgorithmConfig.getTables().put("t_order",
+                new ShadowTableConfiguration(new 
LinkedList<>(Collections.singleton("shadow_group")), new 
LinkedList<>(Collections.singleton("in_used_algorithm"))));
+        inUsedAlgorithmConfig.getTables().put("t_order_empty", new 
ShadowTableConfiguration(new LinkedList<>(), new 
LinkedList<>(Collections.singleton("algorithm_from_empty_table"))));
+        ShadowRuleConfiguration defaultAlgorithmConfig = new 
ShadowRuleConfiguration();
+        
defaultAlgorithmConfig.getShadowAlgorithms().put("default_shadow_algorithm", 
new AlgorithmConfiguration("SQL_HINT", new Properties()));
+        
defaultAlgorithmConfig.setDefaultShadowAlgorithmName("default_shadow_algorithm");
+        return Stream.of(
+                Arguments.of("algorithm not registered", notRegisteredConfig,
+                        new DropShadowAlgorithmStatement(false, 
Collections.singleton("missing_algorithm")), 
UnregisteredAlgorithmException.class),
+                Arguments.of("algorithm in use", inUsedAlgorithmConfig,
+                        new DropShadowAlgorithmStatement(false, 
Collections.singleton("in_used_algorithm")), InUsedAlgorithmException.class),
+                Arguments.of("default algorithm", defaultAlgorithmConfig,
+                        new DropShadowAlgorithmStatement(false, 
Collections.singleton("default_shadow_algorithm")), 
InUsedAlgorithmException.class));
     }
     
-    private DropShadowAlgorithmStatement createSQLStatement(final boolean 
ifExists, final String... ruleName) {
-        return new DropShadowAlgorithmStatement(ifExists, 
Arrays.asList(ruleName));
+    private static Stream<Arguments> hasAnyOneToBeDroppedArguments() {
+        return Stream.of(
+                Arguments.of("contains dropped algorithm", new 
DropShadowAlgorithmStatement(false, Collections.singleton("algorithm_0")), 
true),
+                Arguments.of("contains no dropped algorithm", new 
DropShadowAlgorithmStatement(false, Collections.singleton("algorithm_9")), 
false),
+                Arguments.of("contains one of dropped algorithms", new 
DropShadowAlgorithmStatement(false, Arrays.asList("algorithm_9", 
"algorithm_1")), true));
     }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowRuleExecutorTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowRuleExecutorTest.java
index f3181e1a84e..ab449e2aca4 100644
--- 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowRuleExecutorTest.java
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/DropShadowRuleExecutorTest.java
@@ -17,9 +17,11 @@
 
 package org.apache.shardingsphere.shadow.distsql.handler.update;
 
-import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
+import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleDefinitionExecutor;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
+import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
 import 
org.apache.shardingsphere.shadow.config.datasource.ShadowDataSourceConfiguration;
 import org.apache.shardingsphere.shadow.config.table.ShadowTableConfiguration;
@@ -27,104 +29,144 @@ import 
org.apache.shardingsphere.shadow.distsql.statement.DropShadowRuleStatemen
 import org.apache.shardingsphere.shadow.rule.ShadowRule;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Properties;
+import java.util.stream.Stream;
 
-import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
 class DropShadowRuleExecutorTest {
     
-    private final DropShadowRuleExecutor executor = new 
DropShadowRuleExecutor();
+    private final DropShadowRuleExecutor executor = (DropShadowRuleExecutor) 
TypedSPILoader.getService(DatabaseRuleDefinitionExecutor.class, 
DropShadowRuleStatement.class);
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ShardingSphereDatabase database;
     
     @BeforeEach
     void setUp() {
-        executor.setDatabase(mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS));
+        when(database.getName()).thenReturn("shadow_db");
+        executor.setDatabase(database);
     }
     
-    @Test
-    void assertCheckWithRuleNotExisted() {
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(new 
ShadowRuleConfiguration());
-        executor.setRule(rule);
-        assertThrows(MissingRequiredRuleException.class,
-                () -> 
executor.checkBeforeUpdate(createSQLStatement("notExistedRuleName")));
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("checkBeforeUpdateWithMissingRuleArguments")
+    void assertCheckBeforeUpdateWithMissingRule(final String name, final 
DropShadowRuleStatement sqlStatement) {
+        executor.setRule(createRule(new ShadowRuleConfiguration()));
+        assertThrows(MissingRequiredRuleException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
-    void assertCheckWithIfExists() {
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(new 
ShadowRuleConfiguration());
+    void assertCheckBeforeUpdateWithIfExists() {
+        executor.setRule(createRule(new ShadowRuleConfiguration()));
+        assertDoesNotThrow(() -> 
executor.checkBeforeUpdate(createStatement(true, "missing_rule")));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("hasAnyOneToBeDroppedArguments")
+    void assertHasAnyOneToBeDropped(final String name, final ShadowRule rule, 
final DropShadowRuleStatement sqlStatement, final boolean expected) {
         executor.setRule(rule);
-        executor.checkBeforeUpdate(createSQLStatement(true, 
"notExistedRuleName"));
+        assertThat(executor.hasAnyOneToBeDropped(sqlStatement), is(expected));
     }
     
     @Test
-    void assertUpdateCurrentRuleConfigurationWithUnusedAlgorithms() {
-        DropShadowRuleStatement sqlStatement = 
createSQLStatement("shadow_group");
-        ShadowRuleConfiguration ruleConfig = createCurrentRuleConfiguration();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(ruleConfig);
-        executor.setRule(rule);
+    void assertBuildToBeDroppedRuleConfiguration() {
+        ShadowRuleConfiguration ruleConfig = createRuleConfigurationForDrop();
+        executor.setRule(createRule(ruleConfig));
+        DropShadowRuleStatement sqlStatement = createStatement(false, 
"shadow_group");
         executor.checkBeforeUpdate(sqlStatement);
-        ShadowRuleConfiguration toBeDroppedRuleConfig = 
executor.buildToBeDroppedRuleConfiguration(sqlStatement);
-        assertThat(toBeDroppedRuleConfig.getDataSources().size(), is(1));
-        assertThat(toBeDroppedRuleConfig.getTables().size(), is(1));
-        assertThat(toBeDroppedRuleConfig.getShadowAlgorithms().size(), is(1));
+        ShadowRuleConfiguration actual = 
executor.buildToBeDroppedRuleConfiguration(sqlStatement);
+        assertThat(actual.getDataSources().size(), is(1));
+        assertThat(actual.getDataSources().iterator().next().getName(), 
is("shadow_group"));
+        assertThat(actual.getTables().size(), is(1));
+        assertTrue(actual.getTables().containsKey("t_order"));
+        assertThat(actual.getShadowAlgorithms().size(), is(2));
+        
assertTrue(actual.getShadowAlgorithms().containsKey("only_drop_algorithm"));
+        
assertTrue(actual.getShadowAlgorithms().containsKey("unused_algorithm"));
+        assertThat(ruleConfig.getDataSources().size(), is(1));
+        assertFalse(ruleConfig.getTables().containsKey("t_order"));
+        
assertThat(ruleConfig.getTables().get("t_order_item").getDataSourceNames().size(),
 is(1));
+        
assertThat(ruleConfig.getTables().get("t_order_item").getDataSourceNames().iterator().next(),
 is("shadow_group_1"));
     }
     
     @Test
-    void assertUpdateMultipleCurrentRuleConfigurationWithInUsedAlgorithms() {
-        DropShadowRuleStatement sqlStatement = 
createSQLStatement("shadow_group");
-        ShadowRuleConfiguration ruleConfig = 
createMultipleCurrentRuleConfiguration();
-        ShadowRule rule = mock(ShadowRule.class);
-        when(rule.getConfiguration()).thenReturn(ruleConfig);
-        executor.setRule(rule);
-        executor.checkBeforeUpdate(sqlStatement);
-        ShadowRuleConfiguration toBeDroppedRuleConfig = 
executor.buildToBeDroppedRuleConfiguration(sqlStatement);
-        assertThat(toBeDroppedRuleConfig.getDataSources().size(), is(1));
-        assertThat(toBeDroppedRuleConfig.getTables().size(), is(1));
-        assertThat(toBeDroppedRuleConfig.getShadowAlgorithms().size(), is(1));
+    void assertBuildToBeAlteredRuleConfiguration() {
+        ShadowRuleConfiguration ruleConfig = createRuleConfigurationForDrop();
+        executor.setRule(createRule(ruleConfig));
+        ShadowRuleConfiguration actual = 
executor.buildToBeAlteredRuleConfiguration(createStatement(false, 
"shadow_group"));
+        assertThat(actual.getTables().size(), is(1));
+        assertFalse(actual.getTables().containsKey("t_order"));
+        assertTrue(actual.getTables().containsKey("t_order_item"));
+        
assertThat(actual.getTables().get("t_order_item").getDataSourceNames().size(), 
is(1));
+        
assertThat(actual.getTables().get("t_order_item").getDataSourceNames().iterator().next(),
 is("shadow_group_1"));
     }
     
-    private DropShadowRuleStatement createSQLStatement(final String... 
ruleName) {
-        DropShadowRuleStatement result = new DropShadowRuleStatement(false, 
Arrays.asList(ruleName));
-        result.buildAttributes();
+    private ShadowRuleConfiguration createRuleConfigurationForDrop() {
+        ShadowRuleConfiguration result = new ShadowRuleConfiguration();
+        result.getDataSources().add(new 
ShadowDataSourceConfiguration("shadow_group", "production_0", "shadow_0"));
+        result.getDataSources().add(new 
ShadowDataSourceConfiguration("shadow_group_1", "production_1", "shadow_1"));
+        result.getTables().put("t_order",
+                new ShadowTableConfiguration(new 
ArrayList<>(Collections.singleton("shadow_group")), new 
ArrayList<>(Collections.singleton("only_drop_algorithm"))));
+        result.getTables().put("t_order_item",
+                new ShadowTableConfiguration(new 
ArrayList<>(Arrays.asList("shadow_group", "shadow_group_1")), new 
ArrayList<>(Collections.singleton("shared_algorithm"))));
+        result.getShadowAlgorithms().put("only_drop_algorithm", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        result.getShadowAlgorithms().put("shared_algorithm", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        result.getShadowAlgorithms().put("unused_algorithm", new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        result.setDefaultShadowAlgorithmName("shared_algorithm");
         return result;
     }
     
-    private DropShadowRuleStatement createSQLStatement(final boolean ifExists, 
final String... ruleName) {
-        DropShadowRuleStatement result = new DropShadowRuleStatement(ifExists, 
Arrays.asList(ruleName));
-        result.buildAttributes();
-        return result;
+    @Test
+    void assertGetRuleClass() {
+        assertThat(executor.getRuleClass(), is(ShadowRule.class));
     }
     
-    private ShadowRuleConfiguration createCurrentRuleConfiguration() {
-        ShadowRuleConfiguration result = new ShadowRuleConfiguration();
-        
result.getDataSources().add(createShadowDataSourceConfiguration("shadow_group"));
-        result.getTables().put("t_order", new ShadowTableConfiguration(new 
ArrayList<>(Collections.singleton("shadow_group")), Collections.emptyList()));
-        result.getShadowAlgorithms().put("t_order_algorithm", new 
AlgorithmConfiguration("SHADOW", new Properties()));
-        return result;
+    private static Stream<Arguments> 
checkBeforeUpdateWithMissingRuleArguments() {
+        return Stream.of(
+                Arguments.of("single missing rule", createStatement(false, 
"missing_rule_0")),
+                Arguments.of("multiple missing rules", createStatement(false, 
"missing_rule_0", "missing_rule_1")),
+                Arguments.of("another missing rule", createStatement(false, 
"missing_rule_2")));
     }
     
-    private ShadowRuleConfiguration createMultipleCurrentRuleConfiguration() {
-        ShadowRuleConfiguration result = new ShadowRuleConfiguration();
-        
result.getDataSources().add(createShadowDataSourceConfiguration("shadow_group"));
-        result.getTables().put("t_order", new ShadowTableConfiguration(new 
ArrayList<>(Collections.singleton("shadow_group")), Collections.emptyList()));
-        result.getShadowAlgorithms().put("t_order_algorithm_inUsed", new 
AlgorithmConfiguration("SHADOW", new Properties()));
-        result.getShadowAlgorithms().put("t_order_algorithm_unused", new 
AlgorithmConfiguration("SHADOW", new Properties()));
-        result.setDefaultShadowAlgorithmName("t_order_algorithm_inUsed");
+    private static Stream<Arguments> hasAnyOneToBeDroppedArguments() {
+        ShadowRuleConfiguration ruleConfig = new ShadowRuleConfiguration();
+        ruleConfig.getDataSources().add(new 
ShadowDataSourceConfiguration("shadow_group", "production_0", "shadow_0"));
+        ruleConfig.getDataSources().add(new 
ShadowDataSourceConfiguration("shadow_group_1", "production_1", "shadow_1"));
+        return Stream.of(
+                Arguments.of("contains dropped rule", createRule(ruleConfig), 
createStatement(false, "shadow_group"), true),
+                Arguments.of("contains no dropped rules", 
createRule(ruleConfig), createStatement(false, "missing_rule"), false),
+                Arguments.of("contains one dropped rule", 
createRule(ruleConfig), createStatement(false, "missing_rule", 
"shadow_group_1"), true));
+    }
+    
+    private static DropShadowRuleStatement createStatement(final boolean 
ifExists, final String... ruleNames) {
+        DropShadowRuleStatement result = new DropShadowRuleStatement(ifExists, 
Arrays.asList(ruleNames));
+        result.buildAttributes();
         return result;
     }
     
-    private ShadowDataSourceConfiguration 
createShadowDataSourceConfiguration(final String ruleName) {
-        return new ShadowDataSourceConfiguration(ruleName, "production", 
"shadow");
+    private static ShadowRule createRule(final ShadowRuleConfiguration 
ruleConfig) {
+        ShadowRule result = mock(ShadowRule.class);
+        when(result.getConfiguration()).thenReturn(ruleConfig);
+        return result;
     }
 }
diff --git 
a/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/UnusedAlgorithmFinderTest.java
 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/UnusedAlgorithmFinderTest.java
new file mode 100644
index 00000000000..9999d616e0b
--- /dev/null
+++ 
b/features/shadow/distsql/handler/src/test/java/org/apache/shardingsphere/shadow/distsql/handler/update/UnusedAlgorithmFinderTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.shadow.distsql.handler.update;
+
+import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
+import org.apache.shardingsphere.shadow.config.ShadowRuleConfiguration;
+import org.apache.shardingsphere.shadow.config.table.ShadowTableConfiguration;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Properties;
+import java.util.stream.Stream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+class UnusedAlgorithmFinderTest {
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("findUnusedShadowAlgorithmArguments")
+    void assertFindUnusedShadowAlgorithm(final String name, final 
ShadowRuleConfiguration ruleConfig, final Collection<String> expected) {
+        assertThat(new 
LinkedHashSet<>(UnusedAlgorithmFinder.findUnusedShadowAlgorithm(ruleConfig)), 
is(new LinkedHashSet<>(expected)));
+    }
+    
+    private static Stream<Arguments> findUnusedShadowAlgorithmArguments() {
+        return Stream.of(
+                Arguments.of("table references one algorithm", 
createRuleConfiguration(Collections.singleton("algorithm_used"), null, 
Arrays.asList("algorithm_used", "algorithm_unused")),
+                        Collections.singleton("algorithm_unused")),
+                Arguments.of("table and default algorithm are both in use",
+                        
createRuleConfiguration(Collections.singleton("algorithm_used"), 
"algorithm_default", Arrays.asList("algorithm_used", "algorithm_default", 
"algorithm_unused")),
+                        Collections.singleton("algorithm_unused")),
+                Arguments.of("default algorithm only", 
createRuleConfiguration(Collections.emptyList(), "algorithm_default", 
Arrays.asList("algorithm_default", "algorithm_unused")),
+                        Collections.singleton("algorithm_unused")));
+    }
+    
+    private static ShadowRuleConfiguration createRuleConfiguration(final 
Collection<String> tableAlgorithmNames, final String defaultAlgorithmName, 
final Collection<String> algorithmNames) {
+        ShadowRuleConfiguration result = new ShadowRuleConfiguration();
+        result.getTables().put("t_order", new 
ShadowTableConfiguration(Collections.singletonList("ds_0"), 
tableAlgorithmNames));
+        result.setDefaultShadowAlgorithmName(defaultAlgorithmName);
+        for (String each : algorithmNames) {
+            result.getShadowAlgorithms().put(each, new 
AlgorithmConfiguration("SQL_HINT", new Properties()));
+        }
+        return result;
+    }
+}


Reply via email to