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 bf6c5384f64 Add more test cases on LockClusterExecutorTest (#38033)
bf6c5384f64 is described below

commit bf6c5384f64e396e66ea1e695203b2ec5b3cfb06
Author: Liang Zhang <[email protected]>
AuthorDate: Fri Feb 13 23:53:45 2026 +0800

    Add more test cases on LockClusterExecutorTest (#38033)
---
 .../core/kernel/KernelDistSQLStatementVisitor.java |   4 +-
 .../type/ral/updatable/LockClusterStatement.java   |  13 +--
 .../ral/updatable/lock/LockClusterExecutor.java    |   3 +-
 .../updatable/lock/LockClusterExecutorTest.java    | 100 +++++++++++++++++----
 4 files changed, 88 insertions(+), 32 deletions(-)

diff --git 
a/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
 
b/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
index b9c7239c8e2..20eb588e066 100644
--- 
a/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
+++ 
b/parser/distsql/engine/src/main/java/org/apache/shardingsphere/distsql/parser/core/kernel/KernelDistSQLStatementVisitor.java
@@ -329,7 +329,9 @@ public final class KernelDistSQLStatementVisitor extends 
KernelDistSQLStatementB
     
     @Override
     public ASTNode visitLockCluster(final LockClusterContext ctx) {
-        return new LockClusterStatement((AlgorithmSegment) 
visitAlgorithmDefinition(ctx.lockStrategy().algorithmDefinition()), 
Long.parseLong(IdentifierValueUtils.getValue(ctx.INT_())));
+        String value = IdentifierValueUtils.getValue(ctx.INT_());
+        AlgorithmSegment algorithmSegment = (AlgorithmSegment) 
visitAlgorithmDefinition(ctx.lockStrategy().algorithmDefinition());
+        return null == value ? new LockClusterStatement(algorithmSegment) : 
new LockClusterStatement(algorithmSegment, Long.parseLong(value));
     }
     
     @Override
diff --git 
a/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/type/ral/updatable/LockClusterStatement.java
 
b/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/type/ral/updatable/LockClusterStatement.java
index cb3390c64dd..29f47e67b2f 100644
--- 
a/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/type/ral/updatable/LockClusterStatement.java
+++ 
b/parser/distsql/statement/src/main/java/org/apache/shardingsphere/distsql/statement/type/ral/updatable/LockClusterStatement.java
@@ -21,8 +21,6 @@ import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 
-import java.util.Optional;
-
 /**
  * Lock cluster statement.
  */
@@ -32,14 +30,9 @@ public final class LockClusterStatement extends 
UpdatableRALStatement {
     
     private final AlgorithmSegment lockStrategy;
     
-    private final Long timeoutMillis;
+    private final long timeoutMillis;
     
-    /**
-     * Get lock timeout milliseconds.
-     *
-     * @return lock timeout milliseconds
-     */
-    public Optional<Long> getTimeoutMillis() {
-        return Optional.of(timeoutMillis);
+    public LockClusterStatement(final AlgorithmSegment lockStrategy) {
+        this(lockStrategy, 3000L);
     }
 }
diff --git 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutor.java
 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutor.java
index 9537a0161aa..c48d4fa11b0 100644
--- 
a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutor.java
+++ 
b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutor.java
@@ -41,8 +41,7 @@ public final class LockClusterExecutor implements 
DistSQLUpdateExecutor<LockClus
     public void executeUpdate(final LockClusterStatement sqlStatement, final 
ContextManager contextManager) throws SQLException {
         checkState(contextManager);
         checkAlgorithm(sqlStatement);
-        long timeoutMillis = sqlStatement.getTimeoutMillis().orElse(3000L);
-        contextManager.getExclusiveOperatorEngine().operate(new 
LockClusterOperation(), timeoutMillis, () -> {
+        contextManager.getExclusiveOperatorEngine().operate(new 
LockClusterOperation(), sqlStatement.getTimeoutMillis(), () -> {
             checkState(contextManager);
             TypedSPILoader.getService(ClusterLockStrategy.class, 
sqlStatement.getLockStrategy().getName()).lock();
         });
diff --git 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
index 48c0eeadb44..ae47500eef3 100644
--- 
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
+++ 
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/lock/LockClusterExecutorTest.java
@@ -17,50 +17,112 @@
 
 package 
org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable.lock;
 
+import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import 
org.apache.shardingsphere.distsql.statement.type.ral.updatable.LockClusterStatement;
+import 
org.apache.shardingsphere.infra.algorithm.core.exception.MissingRequiredAlgorithmException;
 import 
org.apache.shardingsphere.infra.spi.exception.ServiceProviderNotFoundException;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.apache.shardingsphere.mode.exclusive.ExclusiveOperatorEngine;
+import 
org.apache.shardingsphere.mode.exclusive.callback.ExclusiveOperationVoidCallback;
 import org.apache.shardingsphere.mode.manager.ContextManager;
 import 
org.apache.shardingsphere.mode.manager.cluster.lock.exception.LockedClusterException;
 import org.apache.shardingsphere.mode.state.ShardingSphereState;
-import org.junit.jupiter.api.Test;
+import org.apache.shardingsphere.mode.state.StatePersistService;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+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.extension.ExtendWith;
-import org.mockito.junit.jupiter.MockitoExtension;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
+import java.sql.SQLException;
 import java.util.Properties;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.eq;
 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(MockitoExtension.class)
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ProxyContext.class)
 class LockClusterExecutorTest {
     
-    private final LockClusterExecutor executor = new LockClusterExecutor();
+    private final LockClusterExecutor executor = (LockClusterExecutor) 
TypedSPILoader.getService(DistSQLUpdateExecutor.class, 
LockClusterStatement.class);
     
-    @SuppressWarnings("resource")
-    @Test
-    void assertExecuteUpdateWithLockedCluster() {
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("provideFailureScenarios")
+    void assertExecuteUpdateWithFailureScenarios(final String name, final 
LockClusterStatement sqlStatement,
+                                                 final ShardingSphereState 
state, final Class<? extends Throwable> expectedException) throws SQLException {
         ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
-        
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.UNAVAILABLE);
-        assertThrows(LockedClusterException.class, () -> 
executor.executeUpdate(new LockClusterStatement(new AlgorithmSegment("FOO", new 
Properties()), null), contextManager));
+        when(contextManager.getStateContext().getState()).thenReturn(state);
+        assertThrows(expectedException, () -> 
executor.executeUpdate(sqlStatement, contextManager));
+        verify(contextManager.getExclusiveOperatorEngine(), 
never()).operate(any(), anyLong(), any());
     }
     
-    @SuppressWarnings("resource")
-    @Test
-    void assertExecuteUpdateWithWrongAlgorithm() {
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("provideOperationScenarios")
+    void assertExecuteUpdateWithOperationScenarios(final String name, final 
LockClusterStatement sqlStatement,
+                                                   final long 
expectedTimeoutMillis, final ShardingSphereState callbackState,
+                                                   final Class<? extends 
Throwable> expectedException, final boolean expectStateUpdated) throws 
SQLException {
         ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
-        
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK);
-        assertThrows(ServiceProviderNotFoundException.class, () -> 
executor.executeUpdate(new LockClusterStatement(new AlgorithmSegment("FOO", new 
Properties()), null), contextManager));
+        ExclusiveOperatorEngine exclusiveOperatorEngine = 
mock(ExclusiveOperatorEngine.class);
+        
when(contextManager.getExclusiveOperatorEngine()).thenReturn(exclusiveOperatorEngine);
+        
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK,
 callbackState);
+        StatePersistService stateService = null;
+        if (expectStateUpdated) {
+            stateService = mock(StatePersistService.class);
+            mockStateService(stateService);
+        }
+        doAnswer(invocation -> {
+            ExclusiveOperationVoidCallback callback = 
invocation.getArgument(2);
+            callback.execute();
+            return null;
+        }).when(exclusiveOperatorEngine).operate(any(), anyLong(), 
any(ExclusiveOperationVoidCallback.class));
+        if (null == expectedException) {
+            assertDoesNotThrow(() -> executor.executeUpdate(sqlStatement, 
contextManager));
+        } else {
+            assertThrows(expectedException, () -> 
executor.executeUpdate(sqlStatement, contextManager));
+        }
+        verify(exclusiveOperatorEngine).operate(any(), 
eq(expectedTimeoutMillis), any(ExclusiveOperationVoidCallback.class));
+        if (expectStateUpdated) {
+            verify(stateService).update(ShardingSphereState.READ_ONLY);
+        }
     }
     
-    @SuppressWarnings("resource")
-    @Test
-    void assertExecuteUpdateWithUsingTimeout() {
+    private void mockStateService(final StatePersistService stateService) {
+        ProxyContext proxyContext = mock(ProxyContext.class);
         ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
-        
when(contextManager.getStateContext().getState()).thenReturn(ShardingSphereState.OK);
-        assertDoesNotThrow(() -> executor.executeUpdate(new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L), 
contextManager));
+        when(proxyContext.getContextManager()).thenReturn(contextManager);
+        
when(contextManager.getPersistServiceFacade().getStateService()).thenReturn(stateService);
+        when(ProxyContext.getInstance()).thenReturn(proxyContext);
+    }
+    
+    private static Stream<Arguments> provideFailureScenarios() {
+        return Stream.of(
+                Arguments.of("cluster state is unavailable", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L),
+                        ShardingSphereState.UNAVAILABLE, 
LockedClusterException.class),
+                Arguments.of("lock strategy is required", new 
LockClusterStatement(null, 2000L), ShardingSphereState.OK, 
MissingRequiredAlgorithmException.class),
+                Arguments.of("lock strategy is unsupported", new 
LockClusterStatement(new AlgorithmSegment("FOO", new Properties()), 2000L),
+                        ShardingSphereState.OK, 
ServiceProviderNotFoundException.class));
+    }
+    
+    private static Stream<Arguments> provideOperationScenarios() {
+        return Stream.of(
+                Arguments.of("use explicit timeout", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 2000L),
+                        2000L, ShardingSphereState.OK, null, true),
+                Arguments.of("use default timeout when absent", new 
LockClusterStatement(new AlgorithmSegment("WRITE", new Properties())),
+                        3000L, ShardingSphereState.OK, null, true),
+                Arguments.of("throw exception when callback state changes", 
new LockClusterStatement(new AlgorithmSegment("WRITE", new Properties()), 
2000L),
+                        2000L, ShardingSphereState.UNAVAILABLE, 
LockedClusterException.class, false));
     }
 }

Reply via email to