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 4123d57278a Add test cases for state, TCL, RAL, label and variable
handlers (#37486)
4123d57278a is described below
commit 4123d57278a0ec204ea7d123e2cbb0e268b7e0f4
Author: Liang Zhang <[email protected]>
AuthorDate: Wed Dec 24 10:47:56 2025 +0800
Add test cases for state, TCL, RAL, label and variable handlers (#37486)
* Add test cases for state, TCL, RAL, label and variable handlers
* Add test cases for state, TCL, RAL, label and variable handlers
* Add test cases for state, TCL, RAL, label and variable handlers
---
.../variable/charset/CharsetSetExecutorTest.java | 75 +++++++++
.../session/SessionVariableRecordExecutorTest.java | 89 +++++++++++
.../label/LabelComputeNodeExecutorTest.java | 92 +++++++++++
.../label/UnlabelComputeNodeExecutorTest.java | 95 +++++++++++
.../RefreshDatabaseMetaDataExecutorTest.java | 67 ++++++++
.../refresh/RefreshTableMetaDataExecutorTest.java | 173 +++++++++++++++++++++
.../BeginTransactionProxyBackendHandlerTest.java | 137 ++++++++++++++++
.../local/type/CommitProxyBackendHandlerTest.java | 100 ++++++++++++
.../ReleaseSavepointProxyBackendHandlerTest.java | 114 ++++++++++++++
.../RollbackSavepointProxyBackendHandlerTest.java | 111 +++++++++++++
.../type/SetAutoCommitProxyBackendHandlerTest.java | 149 ++++++++++++++++++
.../type/SetSavepointProxyBackendHandlerTest.java | 111 +++++++++++++
.../SetTransactionProxyBackendHandlerTest.java | 129 +++++++++++++++
.../ReadOnlyProxyStateCheckerTest.java} | 24 ++-
.../UnavailableProxyStateCheckerTest.java} | 15 +-
.../sysvar/provider/VersionValueProviderTest.java | 4 +-
16 files changed, 1469 insertions(+), 16 deletions(-)
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/charset/CharsetSetExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/charset/CharsetSetExecutorTest.java
new file mode 100644
index 00000000000..e7fdce73818
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/charset/CharsetSetExecutorTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.proxy.backend.handler.admin.executor.variable.charset;
+
+import io.netty.util.Attribute;
+import io.netty.util.AttributeMap;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.database.protocol.constant.CommonConstants;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+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.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class CharsetSetExecutorTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ @Test
+ void assertSetWhenProviderPresentAndVariableMatched() {
+ CharsetVariableProvider provider = mock(CharsetVariableProvider.class);
+
when(provider.getCharsetVariables()).thenReturn(Collections.singletonList("character_set_client"));
+ when(provider.parseCharset("utf8")).thenReturn(StandardCharsets.UTF_8);
+ when(DatabaseTypedSPILoader.findService(CharsetVariableProvider.class,
databaseType)).thenReturn(Optional.of(provider));
+ AttributeMap attributeMap = mock(AttributeMap.class);
+ Attribute attribute = mock(Attribute.class);
+
when(attributeMap.attr(CommonConstants.CHARSET_ATTRIBUTE_KEY)).thenReturn(attribute);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getAttributeMap()).thenReturn(attributeMap);
+ new CharsetSetExecutor(databaseType,
connectionSession).set("CHARACTER_SET_CLIENT", "utf8");
+ verify(attribute).set(StandardCharsets.UTF_8);
+ }
+
+ @Test
+ void assertSetWhenProviderAbsentOrVariableMismatch() {
+ when(DatabaseTypedSPILoader.findService(CharsetVariableProvider.class,
databaseType)).thenReturn(Optional.empty());
+ assertDoesNotThrow(() -> new CharsetSetExecutor(databaseType,
mock()).set("other_variable", "utf8"));
+ }
+
+ @Test
+ void assertSetWhenVariableNotMatched() {
+ CharsetVariableProvider provider = mock(CharsetVariableProvider.class);
+
when(provider.getCharsetVariables()).thenReturn(Collections.singletonList("character_set_server"));
+ when(DatabaseTypedSPILoader.findService(CharsetVariableProvider.class,
databaseType)).thenReturn(Optional.of(provider));
+ assertDoesNotThrow(() -> new CharsetSetExecutor(databaseType,
mock()).set("character_set_client", "utf8"));
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/session/SessionVariableRecordExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/session/SessionVariableRecordExecutorTest.java
new file mode 100644
index 00000000000..e43dd809f55
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/admin/executor/variable/session/SessionVariableRecordExecutorTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.proxy.backend.handler.admin.executor.variable.session;
+
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.RequiredSessionVariableRecorder;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class SessionVariableRecordExecutorTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertRecordSingleVariableWhenNeedReplay() {
+ ReplayedSessionVariableProvider provider =
mock(ReplayedSessionVariableProvider.class);
+ when(provider.isNeedToReplay("autocommit")).thenReturn(true);
+
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class,
databaseType)).thenReturn(Optional.of(provider));
+ RequiredSessionVariableRecorder recorder =
mock(RequiredSessionVariableRecorder.class);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(recorder);
+ new SessionVariableRecordExecutor(databaseType,
connectionSession).recordVariable("autocommit", "1");
+ verify(recorder).setVariable("autocommit", "1");
+ }
+
+ @Test
+ void assertSkipSingleVariableWhenNotNeedReplay() {
+ ReplayedSessionVariableProvider provider =
mock(ReplayedSessionVariableProvider.class);
+
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class,
databaseType)).thenReturn(Optional.of(provider));
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ assertDoesNotThrow(() -> new
SessionVariableRecordExecutor(databaseType,
connectionSession).recordVariable("sql_mode", "STRICT_ALL_TABLES"));
+ }
+
+ @Test
+ void assertRecordVariableWithAllWhenProviderAbsent() {
+
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class,
databaseType)).thenReturn(Optional.empty());
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ assertDoesNotThrow(() -> new
SessionVariableRecordExecutor(databaseType,
connectionSession).recordVariable(Collections.singletonMap("var_a", "1")));
+ }
+
+ @Test
+ void assertRecordOnlyNeededVariables() {
+ ReplayedSessionVariableProvider provider =
mock(ReplayedSessionVariableProvider.class);
+ when(provider.isNeedToReplay("var_a")).thenReturn(true);
+ when(provider.isNeedToReplay("var_b")).thenReturn(false);
+
when(DatabaseTypedSPILoader.findService(ReplayedSessionVariableProvider.class,
databaseType)).thenReturn(Optional.of(provider));
+ RequiredSessionVariableRecorder recorder =
mock(RequiredSessionVariableRecorder.class);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getRequiredSessionVariableRecorder()).thenReturn(recorder);
+ Map<String, String> variables = new HashMap<>(2, 1F);
+ variables.put("var_a", "1");
+ variables.put("var_b", "2");
+ new SessionVariableRecordExecutor(databaseType,
connectionSession).recordVariable(variables);
+ verify(recorder).setVariable("var_a", "1");
+ verify(recorder, never()).setVariable("var_b", "2");
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/LabelComputeNodeExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/LabelComputeNodeExecutorTest.java
new file mode 100644
index 00000000000..0822cb1dcc4
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/LabelComputeNodeExecutorTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.proxy.backend.handler.distsql.ral.updatable.label;
+
+import
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LabelComputeNodeStatement;
+import org.apache.shardingsphere.infra.instance.ClusterInstanceRegistry;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstance;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import
org.apache.shardingsphere.mode.manager.cluster.persist.facade.ClusterPersistServiceFacade;
+import
org.apache.shardingsphere.mode.manager.cluster.persist.service.ClusterComputeNodePersistService;
+import org.apache.shardingsphere.mode.persist.PersistServiceFacade;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class LabelComputeNodeExecutorTest {
+
+ private final LabelComputeNodeExecutor executor =
(LabelComputeNodeExecutor)
TypedSPILoader.getService(DistSQLUpdateExecutor.class,
LabelComputeNodeStatement.class);
+
+ @Test
+ void assertExecuteUpdateWhenInstanceAbsent() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ComputeNodeInstanceContext instanceContext =
mock(ComputeNodeInstanceContext.class);
+ ClusterInstanceRegistry clusterInstanceRegistry =
mock(ClusterInstanceRegistry.class);
+
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+
when(instanceContext.getClusterInstanceRegistry()).thenReturn(clusterInstanceRegistry);
+
when(clusterInstanceRegistry.find("instance-id")).thenReturn(Optional.empty());
+ assertDoesNotThrow(() -> executor.executeUpdate(new
LabelComputeNodeStatement(true, "instance-id",
Collections.singletonList("label_a")), contextManager));
+ }
+
+ @Test
+ void assertExecuteUpdateWhenOverwriteLabels() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ComputeNodeInstance computeNodeInstance =
mock(ComputeNodeInstance.class);
+ ClusterComputeNodePersistService computeNodeService =
mockContextManager(contextManager, computeNodeInstance);
+ ComputeNodeInstanceContext instanceContext =
contextManager.getComputeNodeInstanceContext();
+
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+ executor.executeUpdate(new LabelComputeNodeStatement(true,
"instance-id", Arrays.asList("label_a", "label_b")), contextManager);
+ verify(computeNodeService).persistLabels("instance-id",
Arrays.asList("label_a", "label_b"));
+ }
+
+ @Test
+ void assertExecuteUpdateWhenNotOverwriteLabels() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ComputeNodeInstance computeNodeInstance =
mock(ComputeNodeInstance.class);
+
when(computeNodeInstance.getLabels()).thenReturn(Collections.singletonList("origin_label"));
+ ClusterComputeNodePersistService computeNodeService =
mockContextManager(contextManager, computeNodeInstance);
+ ComputeNodeInstanceContext instanceContext =
contextManager.getComputeNodeInstanceContext();
+
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+ executor.executeUpdate(new LabelComputeNodeStatement(false,
"instance-id", Collections.singletonList("new_label")), contextManager);
+ verify(computeNodeService).persistLabels("instance-id",
Arrays.asList("new_label", "origin_label"));
+ }
+
+ private ClusterComputeNodePersistService mockContextManager(final
ContextManager contextManager, final ComputeNodeInstance computeNodeInstance) {
+ ComputeNodeInstanceContext instanceContext =
mock(ComputeNodeInstanceContext.class, RETURNS_DEEP_STUBS);
+
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+ PersistServiceFacade persistServiceFacade =
mock(PersistServiceFacade.class);
+ ClusterPersistServiceFacade clusterPersistServiceFacade =
mock(ClusterPersistServiceFacade.class);
+ ClusterComputeNodePersistService result =
mock(ClusterComputeNodePersistService.class);
+
when(clusterPersistServiceFacade.getComputeNodeService()).thenReturn(result);
+
when(persistServiceFacade.getModeFacade()).thenReturn(clusterPersistServiceFacade);
+
when(contextManager.getPersistServiceFacade()).thenReturn(persistServiceFacade);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/UnlabelComputeNodeExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/UnlabelComputeNodeExecutorTest.java
new file mode 100644
index 00000000000..120f37f2816
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/label/UnlabelComputeNodeExecutorTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.label;
+
+import
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import
org.apache.shardingsphere.distsql.statement.type.ral.updatable.UnlabelComputeNodeStatement;
+import org.apache.shardingsphere.infra.instance.ClusterInstanceRegistry;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstance;
+import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import
org.apache.shardingsphere.mode.manager.cluster.persist.facade.ClusterPersistServiceFacade;
+import
org.apache.shardingsphere.mode.manager.cluster.persist.service.ClusterComputeNodePersistService;
+import org.apache.shardingsphere.mode.persist.PersistServiceFacade;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.when;
+
+class UnlabelComputeNodeExecutorTest {
+
+ private final UnlabelComputeNodeExecutor executor =
(UnlabelComputeNodeExecutor)
TypedSPILoader.getService(DistSQLUpdateExecutor.class,
UnlabelComputeNodeStatement.class);
+
+ @Test
+ void assertDoNothingWhenInstanceAbsent() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ComputeNodeInstanceContext instanceContext =
mock(ComputeNodeInstanceContext.class);
+ ClusterInstanceRegistry clusterInstanceRegistry =
mock(ClusterInstanceRegistry.class);
+
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+
when(instanceContext.getClusterInstanceRegistry()).thenReturn(clusterInstanceRegistry);
+
when(clusterInstanceRegistry.find("instance-id")).thenReturn(Optional.empty());
+ PersistServiceFacade persistServiceFacade =
mock(PersistServiceFacade.class);
+
when(contextManager.getPersistServiceFacade()).thenReturn(persistServiceFacade);
+ executor.executeUpdate(new UnlabelComputeNodeStatement("instance-id",
Collections.singletonList("label_a")), contextManager);
+ verifyNoInteractions(persistServiceFacade);
+ }
+
+ @Test
+ void assertClearLabelsWhenStatementLabelsEmpty() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ComputeNodeInstance computeNodeInstance =
mock(ComputeNodeInstance.class);
+ ClusterComputeNodePersistService computeNodeService =
mockContextManager(contextManager, computeNodeInstance);
+ ComputeNodeInstanceContext instanceContext =
contextManager.getComputeNodeInstanceContext();
+
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+ executor.executeUpdate(new UnlabelComputeNodeStatement("instance-id",
Collections.emptyList()), contextManager);
+ verify(computeNodeService).persistLabels("instance-id",
Collections.emptyList());
+ }
+
+ @Test
+ void assertRemoveSpecifiedLabels() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ComputeNodeInstance computeNodeInstance =
mock(ComputeNodeInstance.class);
+
when(computeNodeInstance.getLabels()).thenReturn(Arrays.asList("label_a",
"label_b"));
+ ClusterComputeNodePersistService computeNodeService =
mockContextManager(contextManager, computeNodeInstance);
+ ComputeNodeInstanceContext instanceContext =
contextManager.getComputeNodeInstanceContext();
+
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+ executor.executeUpdate(new UnlabelComputeNodeStatement("instance-id",
Collections.singletonList("label_b")), contextManager);
+ verify(computeNodeService).persistLabels("instance-id",
Collections.singletonList("label_a"));
+ }
+
+ private ClusterComputeNodePersistService mockContextManager(final
ContextManager contextManager, final ComputeNodeInstance computeNodeInstance) {
+ ComputeNodeInstanceContext instanceContext =
mock(ComputeNodeInstanceContext.class, RETURNS_DEEP_STUBS);
+
when(instanceContext.getClusterInstanceRegistry().find("instance-id")).thenReturn(Optional.of(computeNodeInstance));
+
when(contextManager.getComputeNodeInstanceContext()).thenReturn(instanceContext);
+ PersistServiceFacade persistServiceFacade =
mock(PersistServiceFacade.class);
+ ClusterPersistServiceFacade clusterPersistServiceFacade =
mock(ClusterPersistServiceFacade.class);
+
when(persistServiceFacade.getModeFacade()).thenReturn(clusterPersistServiceFacade);
+
when(contextManager.getPersistServiceFacade()).thenReturn(persistServiceFacade);
+ ClusterComputeNodePersistService result =
mock(ClusterComputeNodePersistService.class);
+
when(clusterPersistServiceFacade.getComputeNodeService()).thenReturn(result);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshDatabaseMetaDataExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshDatabaseMetaDataExecutorTest.java
new file mode 100644
index 00000000000..3d49c29c4d1
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshDatabaseMetaDataExecutorTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.refresh;
+
+import
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import
org.apache.shardingsphere.distsql.statement.type.ral.updatable.RefreshDatabaseMetaDataStatement;
+import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import
org.apache.shardingsphere.infra.metadata.database.schema.util.SystemSchemaUtils;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RefreshDatabaseMetaDataExecutorTest {
+
+ private final RefreshDatabaseMetaDataExecutor executor =
(RefreshDatabaseMetaDataExecutor)
TypedSPILoader.getService(DistSQLUpdateExecutor.class,
RefreshDatabaseMetaDataStatement.class);
+
+ @Test
+ void assertRefreshSpecifiedDatabase() {
+ ContextManager contextManager = mock(ContextManager.class);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(contextManager.getDatabase("db0")).thenReturn(database);
+ try (MockedStatic<SystemSchemaUtils> mockedStatic =
mockStatic(SystemSchemaUtils.class)) {
+ mockedStatic.when(() ->
SystemSchemaUtils.isSystemSchema(database)).thenReturn(false);
+ executor.executeUpdate(new RefreshDatabaseMetaDataStatement("db0",
false), contextManager);
+ verify(contextManager).reloadDatabase(database);
+ }
+ }
+
+ @Test
+ void assertRefreshAllDatabasesExceptSystem() {
+ ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
+ ShardingSphereDatabase systemDatabase =
mock(ShardingSphereDatabase.class);
+ ShardingSphereDatabase normalDatabase =
mock(ShardingSphereDatabase.class);
+ Collection<ShardingSphereDatabase> databases =
Arrays.asList(systemDatabase, normalDatabase);
+
when(contextManager.getMetaDataContexts().getMetaData().getAllDatabases()).thenReturn(databases);
+ try (MockedStatic<SystemSchemaUtils> mockedStatic =
mockStatic(SystemSchemaUtils.class)) {
+ mockedStatic.when(() ->
SystemSchemaUtils.isSystemSchema(systemDatabase)).thenReturn(true);
+ executor.executeUpdate(new RefreshDatabaseMetaDataStatement(null,
false), contextManager);
+ verify(contextManager).reloadDatabase(normalDatabase);
+ }
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
new file mode 100644
index 00000000000..1ad17bc115c
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/refresh/RefreshTableMetaDataExecutorTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.proxy.backend.handler.distsql.ral.updatable.refresh;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
+import
org.apache.shardingsphere.distsql.statement.type.ral.updatable.RefreshTableMetaDataStatement;
+import
org.apache.shardingsphere.infra.exception.kernel.metadata.SchemaNotFoundException;
+import
org.apache.shardingsphere.infra.exception.kernel.metadata.TableNotFoundException;
+import
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.EmptyStorageUnitException;
+import
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.MissingRequiredStorageUnitsException;
+import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
+import
org.apache.shardingsphere.infra.metadata.database.resource.unit.StorageUnit;
+import
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RefreshTableMetaDataExecutorTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ private final RefreshTableMetaDataExecutor executor =
(RefreshTableMetaDataExecutor)
TypedSPILoader.getService(DistSQLUpdateExecutor.class,
RefreshTableMetaDataStatement.class);
+
+ @Test
+ void assertExecuteUpdateWithReloadTableWithStorageUnit() {
+ ShardingSphereDatabase database = mockDatabase(true);
+ ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+ when(schema.containsTable("t_order")).thenReturn(true);
+ when(database.getSchema("logic_schema")).thenReturn(schema);
+ ContextManager contextManager = mock(ContextManager.class);
+ executor.setDatabase(database);
+ executor.executeUpdate(new RefreshTableMetaDataStatement("t_order",
"ds_0", "logic_schema"), contextManager);
+ verify(contextManager).reloadTable(database, "logic_schema", "ds_0",
"t_order");
+ }
+
+ @Test
+ void assertExecuteUpdateWithReloadSchemaWithStorageUnit() {
+ RefreshTableMetaDataStatement sqlStatement = new
RefreshTableMetaDataStatement(null, "ds_0", "logic_schema");
+ ShardingSphereDatabase database = mockDatabase(true);
+ ContextManager contextManager = mock(ContextManager.class);
+ executor.setDatabase(database);
+ executor.executeUpdate(sqlStatement, contextManager);
+ verify(contextManager).reloadSchema(database, "logic_schema", "ds_0");
+ }
+
+ @Test
+ void assertExecuteUpdateWithReloadTableWithoutStorageUnit() {
+ RefreshTableMetaDataStatement sqlStatement = new
RefreshTableMetaDataStatement("t_order", null, null);
+ ShardingSphereDatabase database = mockDatabase(true);
+ when(database.getProtocolType()).thenReturn(databaseType);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData();
+ ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+ when(schema.containsTable("t_order")).thenReturn(true);
+ when(database.getSchema("public")).thenReturn(schema);
+ ContextManager contextManager = mock(ContextManager.class);
+ executor.setDatabase(database);
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ executor.executeUpdate(sqlStatement, contextManager);
+ }
+ verify(contextManager).reloadTable(database, "public", "t_order");
+ }
+
+ @Test
+ void assertExecuteUpdateWithReloadDatabase() {
+ RefreshTableMetaDataStatement sqlStatement = new
RefreshTableMetaDataStatement(null, null, null);
+ ShardingSphereDatabase database = mockDatabase(true);
+ when(database.getProtocolType()).thenReturn(databaseType);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData();
+ ContextManager contextManager = mock(ContextManager.class);
+ executor.setDatabase(database);
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ executor.executeUpdate(sqlStatement, contextManager);
+ }
+ verify(contextManager).reloadDatabase(database);
+ }
+
+ @Test
+ void assertExecuteUpdateWithEmptyStorageUnits() {
+ RefreshTableMetaDataStatement sqlStatement = new
RefreshTableMetaDataStatement(null, null, null);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(database.getName()).thenReturn("logic_db");
+ when(database.getProtocolType()).thenReturn(databaseType);
+ ResourceMetaData resourceMetaData = mock(ResourceMetaData.class);
+ when(database.getResourceMetaData()).thenReturn(resourceMetaData);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData();
+ executor.setDatabase(database);
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(EmptyStorageUnitException.class, () ->
executor.executeUpdate(sqlStatement, mock(ContextManager.class)));
+ }
+ }
+
+ @Test
+ void assertExecuteUpdateWithMissingStorageUnit() {
+ RefreshTableMetaDataStatement sqlStatement = new
RefreshTableMetaDataStatement(null, "miss_ds", null);
+ ShardingSphereDatabase database = mockDatabase(true);
+ when(database.getProtocolType()).thenReturn(databaseType);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData();
+ executor.setDatabase(database);
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(MissingRequiredStorageUnitsException.class, () ->
executor.executeUpdate(sqlStatement, mock(ContextManager.class)));
+ }
+ }
+
+ @Test
+ void assertThrowWhenSchemaMissing() {
+ RefreshTableMetaDataStatement sqlStatement = new
RefreshTableMetaDataStatement(null, null, "absent_schema");
+ ShardingSphereDatabase database = mockDatabase(false);
+ executor.setDatabase(database);
+ assertThrows(SchemaNotFoundException.class, () ->
executor.executeUpdate(sqlStatement, mock(ContextManager.class)));
+ }
+
+ @Test
+ void assertThrowWhenTableMissing() {
+ ShardingSphereDatabase database = mockDatabase(true);
+ ShardingSphereSchema schema = mock(ShardingSphereSchema.class);
+ when(schema.containsTable("missing_table")).thenReturn(false);
+ when(database.getSchema("logic_schema")).thenReturn(schema);
+ executor.setDatabase(database);
+ assertThrows(TableNotFoundException.class, () ->
executor.executeUpdate(new RefreshTableMetaDataStatement("missing_table", null,
"logic_schema"), mock(ContextManager.class)));
+ }
+
+ private ShardingSphereDatabase mockDatabase(final boolean schemaExists) {
+ ShardingSphereDatabase result = mock(ShardingSphereDatabase.class,
RETURNS_DEEP_STUBS);
+ when(result.getName()).thenReturn("logic_db");
+
when(result.getResourceMetaData().getStorageUnits()).thenReturn(Collections.singletonMap("ds_0",
mock(StorageUnit.class)));
+ when(result.containsSchema(anyString())).thenReturn(schemaExists);
+ return result;
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData() {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.of("public"));
+ when(result.getSchemaOption()).thenReturn(schemaOption);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..f4320648697
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/BeginTransactionProxyBackendHandlerTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.database.exception.core.exception.transaction.InTransactionException;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.TCLStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class BeginTransactionProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertBeginWhenNotInTransaction() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(false, "public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new BeginTransactionProxyBackendHandler(mock(TCLStatement.class),
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).begin();
+ verify(transactionManager, never()).commit();
+ }
+ }
+
+ @Test
+ void assertBeginWithNestedTransactionCommit() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(true, "public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new BeginTransactionProxyBackendHandler(mock(TCLStatement.class),
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).commit();
+ verify(transactionManager).begin();
+ }
+ }
+
+ @Test
+ void assertThrowWhenNestedTransactionUnsupportedWithDefaultSchema() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(false, "public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager> ignored =
mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(InTransactionException.class, () -> new
BeginTransactionProxyBackendHandler(mock(TCLStatement.class),
connectionSession).execute());
+ }
+ }
+
+ @Test
+ void assertBeginWhenDefaultSchemaNotPresent() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(false, null);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new BeginTransactionProxyBackendHandler(mock(TCLStatement.class),
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager, never()).commit();
+ verify(transactionManager).begin();
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final boolean
supportAutoCommitInNestedTransaction, final String defaultSchema) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectTransactionOption transactionOption = new
DialectTransactionOption(false, false, supportAutoCommitInNestedTransaction,
false, true,
+ Connection.TRANSACTION_READ_COMMITTED, false, false,
Collections.emptyList());
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+ when(result.getTransactionOption()).thenReturn(transactionOption);
+ when(result.getSchemaOption()).thenReturn(schemaOption);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/CommitProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/CommitProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..fc4b946407c
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/CommitProxyBackendHandlerTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
+import
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.RollbackStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.TCLStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class CommitProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertReturnRollbackStatementWhenCommitFailed() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+ ConnectionContext connectionContext = new
ConnectionContext(Collections::emptyList);
+ connectionContext.getTransactionContext().setExceptionOccur(true);
+
when(connectionSession.getConnectionContext()).thenReturn(connectionContext);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ TCLStatement sqlStatement = mock(TCLStatement.class);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ ResponseHeader actual = new
CommitProxyBackendHandler(sqlStatement, connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).commit();
+ assertThat(((UpdateResponseHeader) actual).getSqlStatement(),
instanceOf(RollbackStatement.class));
+ }
+ }
+
+ @Test
+ void assertReturnOriginalStatementWhenNoException() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(false);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+ ConnectionContext connectionContext = new
ConnectionContext(Collections::emptyList);
+
when(connectionSession.getConnectionContext()).thenReturn(connectionContext);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ TCLStatement sqlStatement = mock(TCLStatement.class);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ ResponseHeader actual = new
CommitProxyBackendHandler(sqlStatement, connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).commit();
+ assertThat(((UpdateResponseHeader) actual).getSqlStatement(),
is(sqlStatement));
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final boolean
returnRollbackWhenFailed) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ when(result.getTransactionOption()).thenReturn(new
DialectTransactionOption(
+ false, false, false, false, true,
Connection.TRANSACTION_READ_COMMITTED, returnRollbackWhenFailed, false,
Collections.emptyList()));
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/ReleaseSavepointProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/ReleaseSavepointProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..285be3c677b
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/ReleaseSavepointProxyBackendHandlerTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.ReleaseSavepointStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class ReleaseSavepointProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertReleaseSavepoint() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData("public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ ReleaseSavepointStatement sqlStatement =
mock(ReleaseSavepointStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn("sp_release");
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new ReleaseSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).releaseSavepoint("sp_release");
+ }
+ }
+
+ @Test
+ void assertReleaseWithDefaultSchemaMissing() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(null);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ ReleaseSavepointStatement sqlStatement =
mock(ReleaseSavepointStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn("sp_release");
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new ReleaseSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).releaseSavepoint("sp_release");
+ }
+ }
+
+ @Test
+ void assertReleaseWithInvalidStatus() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData("public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ ReleaseSavepointStatement sqlStatement =
mock(ReleaseSavepointStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn("sp_release");
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager> ignored =
mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(SQLFeatureNotSupportedException.class, () -> new
ReleaseSavepointProxyBackendHandler(sqlStatement, connectionSession).execute());
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final String
defaultSchema) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+ when(result.getSchemaOption()).thenReturn(schemaOption);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/RollbackSavepointProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/RollbackSavepointProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..768accb279e
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/RollbackSavepointProxyBackendHandlerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.RollbackStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class RollbackSavepointProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertRollbackToSavepoint() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData("public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ RollbackStatement sqlStatement = mock(RollbackStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn(Optional.of("sp1"));
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new RollbackSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).rollbackTo("sp1");
+ }
+ }
+
+ @Test
+ void assertRollbackWithEmptySavepointName() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(null);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getTransactionStatus()).thenReturn(new
TransactionStatus());
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ RollbackStatement sqlStatement = mock(RollbackStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn(Optional.empty());
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new RollbackSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).rollbackTo("");
+ }
+ }
+
+ @Test
+ void assertExecuteWithInvalidStatus() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData("public");
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getTransactionStatus()).thenReturn(new
TransactionStatus());
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ RollbackStatement sqlStatement = mock(RollbackStatement.class);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager> ignored =
mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(SQLFeatureNotSupportedException.class, () -> new
RollbackSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute());
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final String
defaultSchema) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+ when(result.getSchemaOption()).thenReturn(schemaOption);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetAutoCommitProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetAutoCommitProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..76ece8bfe4a
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetAutoCommitProxyBackendHandlerTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
+import
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.SetAutoCommitStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SetAutoCommitProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertExecuteCommitWhenNestedTransactionSupported() throws
SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(true);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SetAutoCommitStatement sqlStatement =
mock(SetAutoCommitStatement.class);
+ when(sqlStatement.isAutoCommit()).thenReturn(true);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ ResponseHeader actual = new
SetAutoCommitProxyBackendHandler(sqlStatement, connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).commit();
+ verify(connectionSession).setAutoCommit(true);
+ assertThat(((UpdateResponseHeader) actual).getSqlStatement(),
is(sqlStatement));
+ }
+ }
+
+ @Test
+ void assertExecuteWithoutCommitWhenNestedTransactionUnsupported() throws
SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(false);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SetAutoCommitStatement sqlStatement =
mock(SetAutoCommitStatement.class);
+ when(sqlStatement.isAutoCommit()).thenReturn(true);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertDoesNotThrow(() -> new
SetAutoCommitProxyBackendHandler(sqlStatement, connectionSession).execute());
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(connectionSession).setAutoCommit(true);
+ verify(transactionManager, never()).commit();
+ }
+ }
+
+ @Test
+ void assertExecuteWhenAutoCommitDisabled() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(true);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SetAutoCommitStatement sqlStatement =
mock(SetAutoCommitStatement.class);
+ when(sqlStatement.isAutoCommit()).thenReturn(false);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new SetAutoCommitProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager, never()).commit();
+ verify(connectionSession).setAutoCommit(false);
+ }
+ }
+
+ @Test
+ void assertExecuteWhenNotInTransaction() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(true);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(false);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SetAutoCommitStatement sqlStatement =
mock(SetAutoCommitStatement.class);
+ when(sqlStatement.isAutoCommit()).thenReturn(true);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new SetAutoCommitProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager, never()).commit();
+ verify(connectionSession).setAutoCommit(true);
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final boolean
supportAutoCommitInNestedTransaction) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectTransactionOption transactionOption = new
DialectTransactionOption(false, false, supportAutoCommitInNestedTransaction,
false, true,
+ Connection.TRANSACTION_READ_COMMITTED, false, false,
Collections.emptyList());
+ when(result.getTransactionOption()).thenReturn(transactionOption);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetSavepointProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetSavepointProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..ae8484dadd4
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetSavepointProxyBackendHandlerTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.schema.DialectSchemaOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.SavepointStatement;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
+
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SetSavepointProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertExecuteWithTransaction() throws SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData("public");
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SavepointStatement sqlStatement = mock(SavepointStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn("foo_point");
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new SetSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).setSavepoint("foo_point");
+ }
+ }
+
+ @Test
+ void assertExecuteWithoutTransactionButNoDefaultSchema() throws
SQLException {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(null);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getTransactionStatus()).thenReturn(new
TransactionStatus());
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SavepointStatement sqlStatement = mock(SavepointStatement.class);
+ when(sqlStatement.getSavepointName()).thenReturn("bar_point");
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager>
mockedConstruction = mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new SetSavepointProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ ProxyBackendTransactionManager transactionManager =
mockedConstruction.constructed().get(0);
+ verify(transactionManager).setSavepoint("bar_point");
+ }
+ }
+
+ @Test
+ void assertExecuteWithInvalidStatus() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData("public");
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getTransactionStatus()).thenReturn(new
TransactionStatus());
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+
when(connectionSession.getDatabaseConnectionManager()).thenReturn(mock(ProxyDatabaseConnectionManager.class));
+ SavepointStatement sqlStatement = mock(SavepointStatement.class);
+ try (
+ MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedConstruction<ProxyBackendTransactionManager> ignored =
mockConstruction(ProxyBackendTransactionManager.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(SQLFeatureNotSupportedException.class, () -> new
SetSavepointProxyBackendHandler(sqlStatement, connectionSession).execute());
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final String
defaultSchema) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectSchemaOption schemaOption = mock(DialectSchemaOption.class);
+
when(schemaOption.getDefaultSchema()).thenReturn(Optional.ofNullable(defaultSchema));
+ when(result.getSchemaOption()).thenReturn(schemaOption);
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetTransactionProxyBackendHandlerTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetTransactionProxyBackendHandlerTest.java
new file mode 100644
index 00000000000..6635da40e4d
--- /dev/null
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/tcl/local/type/SetTransactionProxyBackendHandlerTest.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.proxy.backend.handler.tcl.local.type;
+
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
+import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.backend.session.transaction.TransactionStatus;
+import
org.apache.shardingsphere.sql.parser.statement.core.enums.TransactionAccessType;
+import
org.apache.shardingsphere.sql.parser.statement.core.enums.TransactionIsolationLevel;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.SetTransactionStatement;
+import
org.apache.shardingsphere.transaction.exception.SwitchTypeInTransactionException;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.sql.Connection;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class SetTransactionProxyBackendHandlerTest {
+
+ private final DatabaseType databaseType = mock(DatabaseType.class);
+
+ @Test
+ void assertExecuteWhenSwitchTypeInTransaction() {
+ TransactionStatus transactionStatus = new TransactionStatus();
+ transactionStatus.setInTransaction(true);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+ SetTransactionStatement sqlStatement =
mock(SetTransactionStatement.class);
+ when(sqlStatement.containsScope()).thenReturn(false);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(Connection.TRANSACTION_READ_COMMITTED);
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ assertThrows(SwitchTypeInTransactionException.class, () -> new
SetTransactionProxyBackendHandler(sqlStatement, connectionSession).execute());
+ }
+ }
+
+ @Test
+ void assertExecuteWhenSetReadOnly() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(Connection.TRANSACTION_READ_COMMITTED);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+ SetTransactionStatement sqlStatement =
mock(SetTransactionStatement.class);
+ when(sqlStatement.containsScope()).thenReturn(true);
+
when(sqlStatement.isDesiredAccessMode(TransactionAccessType.READ_ONLY)).thenReturn(true);
+ when(sqlStatement.getIsolationLevel()).thenReturn(Optional.empty());
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ UpdateResponseHeader actual = (UpdateResponseHeader) new
SetTransactionProxyBackendHandler(sqlStatement, connectionSession).execute();
+ verify(connectionSession).setReadOnly(true);
+ assertThat(actual.getSqlStatement(), is(sqlStatement));
+ }
+ }
+
+ @Test
+ void assertExecuteWhenSetReadWrite() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(Connection.TRANSACTION_READ_COMMITTED);
+ TransactionStatus transactionStatus = new TransactionStatus();
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+
when(connectionSession.getTransactionStatus()).thenReturn(transactionStatus);
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+ SetTransactionStatement sqlStatement =
mock(SetTransactionStatement.class);
+ when(sqlStatement.containsScope()).thenReturn(true);
+
when(sqlStatement.isDesiredAccessMode(TransactionAccessType.READ_WRITE)).thenReturn(true);
+ when(sqlStatement.getIsolationLevel()).thenReturn(Optional.empty());
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new SetTransactionProxyBackendHandler(sqlStatement,
connectionSession).execute();
+ verify(connectionSession).setReadOnly(false);
+ }
+ }
+
+ @Test
+ void assertExecuteWhenSetIsolationLevel() {
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mockDialectDatabaseMetaData(Connection.TRANSACTION_SERIALIZABLE);
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getTransactionStatus()).thenReturn(new
TransactionStatus());
+ when(connectionSession.getProtocolType()).thenReturn(databaseType);
+ SetTransactionStatement sqlStatement =
mock(SetTransactionStatement.class);
+ when(sqlStatement.containsScope()).thenReturn(false);
+
when(sqlStatement.isDesiredAccessMode(Mockito.any())).thenReturn(false);
+
when(sqlStatement.getIsolationLevel()).thenReturn(Optional.of(TransactionIsolationLevel.SERIALIZABLE));
+ try (MockedStatic<DatabaseTypedSPILoader> mockedStatic =
mockStatic(DatabaseTypedSPILoader.class)) {
+ mockedStatic.when(() ->
DatabaseTypedSPILoader.getService(DialectDatabaseMetaData.class,
databaseType)).thenReturn(dialectDatabaseMetaData);
+ new SetTransactionProxyBackendHandler(sqlStatement,
connectionSession).execute();
+
verify(connectionSession).setDefaultIsolationLevel(TransactionIsolationLevel.SERIALIZABLE);
+
verify(connectionSession).setIsolationLevel(TransactionIsolationLevel.SERIALIZABLE);
+ }
+ }
+
+ private DialectDatabaseMetaData mockDialectDatabaseMetaData(final int
defaultIsolationLevel) {
+ DialectDatabaseMetaData result = mock(DialectDatabaseMetaData.class);
+ DialectTransactionOption transactionOption = new
DialectTransactionOption(false, false, false, false, true,
defaultIsolationLevel, false, false, Collections.emptyList());
+ doReturn(transactionOption).when(result).getTransactionOption();
+ return result;
+ }
+}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/ReadOnlyProxyStateTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/ReadOnlyProxyStateCheckerTest.java
similarity index 50%
rename from
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/ReadOnlyProxyStateTest.java
rename to
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/ReadOnlyProxyStateCheckerTest.java
index 7ff4df4eb04..3af3c640fbf 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/ReadOnlyProxyStateTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/ReadOnlyProxyStateCheckerTest.java
@@ -15,26 +15,34 @@
* limitations under the License.
*/
-package org.apache.shardingsphere.proxy.backend.state.impl;
+package org.apache.shardingsphere.proxy.backend.state.type;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.distsql.statement.type.ral.updatable.UnlockClusterStatement;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.mode.exception.ShardingSphereStateException;
-import
org.apache.shardingsphere.proxy.backend.state.type.ReadOnlyProxyStateChecker;
+import org.apache.shardingsphere.mode.state.ShardingSphereState;
+import org.apache.shardingsphere.proxy.backend.state.ProxyClusterStateChecker;
import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
-import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
-class ReadOnlyProxyStateTest {
+class ReadOnlyProxyStateCheckerTest {
+
+ private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+
+ private final ProxyClusterStateChecker stateChecker =
TypedSPILoader.getService(ProxyClusterStateChecker.class,
ShardingSphereState.READ_ONLY);
@Test
- void assertExecuteWithUnsupportedSQL() {
- assertThrows(ShardingSphereStateException.class, () -> new
ReadOnlyProxyStateChecker().check(mock(InsertStatement.class), mock()));
+ void assertCheckUnsupportedSQL() {
+ assertThrows(ShardingSphereStateException.class, () ->
stateChecker.check(mock(InsertStatement.class), databaseType));
}
@Test
- void assertExecuteWithSupportedSQL() {
- new ReadOnlyProxyStateChecker().check(mock(SelectStatement.class),
mock());
+ void assertCheckSupportedSQL() {
+ assertDoesNotThrow(() ->
stateChecker.check(mock(UnlockClusterStatement.class), databaseType));
}
}
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/UnavailableProxyStateTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/UnavailableProxyStateCheckerTest.java
similarity index 80%
rename from
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/UnavailableProxyStateTest.java
rename to
proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/UnavailableProxyStateCheckerTest.java
index 8c3769340d4..5055006342c 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/impl/UnavailableProxyStateTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/state/type/UnavailableProxyStateCheckerTest.java
@@ -15,15 +15,16 @@
* limitations under the License.
*/
-package org.apache.shardingsphere.proxy.backend.state.impl;
+package org.apache.shardingsphere.proxy.backend.state.type;
import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
import
org.apache.shardingsphere.distsql.statement.type.ral.updatable.ImportMetaDataStatement;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.mode.exception.ShardingSphereStateException;
+import org.apache.shardingsphere.mode.state.ShardingSphereState;
import
org.apache.shardingsphere.proxy.backend.state.DialectProxyStateSupportedSQLProvider;
-import
org.apache.shardingsphere.proxy.backend.state.type.UnavailableProxyStateChecker;
+import org.apache.shardingsphere.proxy.backend.state.ProxyClusterStateChecker;
import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DMLStatement;
import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
@@ -40,20 +41,22 @@ import static org.mockito.Mockito.when;
@ExtendWith(AutoMockExtension.class)
@StaticMockSettings(DatabaseTypedSPILoader.class)
-class UnavailableProxyStateTest {
+class UnavailableProxyStateCheckerTest {
private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+ private final ProxyClusterStateChecker stateChecker =
TypedSPILoader.getService(ProxyClusterStateChecker.class,
ShardingSphereState.UNAVAILABLE);
+
@Test
void assertExecuteWithUnsupportedSQL() {
when(DatabaseTypedSPILoader.findService(DialectProxyStateSupportedSQLProvider.class,
databaseType)).thenReturn(Optional.empty());
- assertThrows(ShardingSphereStateException.class, () -> new
UnavailableProxyStateChecker().check(mock(DMLStatement.class), databaseType));
+ assertThrows(ShardingSphereStateException.class, () ->
stateChecker.check(mock(DMLStatement.class), databaseType));
}
@Test
void assertExecuteWithSupportedSQL() {
when(DatabaseTypedSPILoader.findService(DialectProxyStateSupportedSQLProvider.class,
databaseType)).thenReturn(Optional.empty());
- assertDoesNotThrow(() -> new
UnavailableProxyStateChecker().check(mock(ImportMetaDataStatement.class),
databaseType));
+ assertDoesNotThrow(() ->
stateChecker.check(mock(ImportMetaDataStatement.class), databaseType));
}
@Test
@@ -61,6 +64,6 @@ class UnavailableProxyStateTest {
DialectProxyStateSupportedSQLProvider supportedSQLProvider =
mock(DialectProxyStateSupportedSQLProvider.class);
when(supportedSQLProvider.getSupportedSQLStatementTypesOnUnavailableState()).thenReturn(Collections.singleton(DMLStatement.class));
when(DatabaseTypedSPILoader.findService(DialectProxyStateSupportedSQLProvider.class,
databaseType)).thenReturn(Optional.of(supportedSQLProvider));
- assertDoesNotThrow(() -> new
UnavailableProxyStateChecker().check(mock(DMLStatement.class), databaseType));
+ assertDoesNotThrow(() -> stateChecker.check(mock(DMLStatement.class),
databaseType));
}
}
diff --git
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
index b577306a53b..3473623438d 100644
---
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
+++
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/provider/VersionValueProviderTest.java
@@ -30,10 +30,10 @@ import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockS
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
-import org.mockito.Mockito;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mockStatic;
@ExtendWith(AutoMockExtension.class)
@StaticMockSettings(ProxyContext.class)
@@ -42,7 +42,7 @@ class VersionValueProviderTest {
@Test
void assertGetValue() {
DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "MySQL");
- try (MockedStatic<DatabaseProtocolServerInfo> mockedStatic =
Mockito.mockStatic(DatabaseProtocolServerInfo.class)) {
+ try (MockedStatic<DatabaseProtocolServerInfo> mockedStatic =
mockStatic(DatabaseProtocolServerInfo.class)) {
mockedStatic.when(() ->
DatabaseProtocolServerInfo.getProtocolVersion(null,
databaseType)).thenReturn("8.0");
ConnectionSession connectionSession = new
ConnectionSession(databaseType, new DefaultAttributeMap());
assertThat(new
VersionValueProvider().get(MySQLSystemVariableScope.GLOBAL, connectionSession,
MySQLSystemVariable.VERSION), is("8.0"));