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 d207a303059 Add test cases on GlobalClockTransactionHook (#32944)
d207a303059 is described below

commit d207a303059eaf65816f3b8380acf763c2c5fcc4
Author: Liang Zhang <[email protected]>
AuthorDate: Sat Sep 21 04:00:55 2024 +0800

    Add test cases on GlobalClockTransactionHook (#32944)
    
    * Add test cases on OpenGaussGlobalClockTransactionExecutor
    
    * Refactor GlobalClockTransactionHook
    
    * Add test cases on GlobalClockTransactionHook
---
 .../executor/GlobalClockTransactionHook.java       |  19 ++-
 .../OpenGaussGlobalClockTransactionExecutor.java   |   2 +-
 .../executor/GlobalClockTransactionHookTest.java   | 152 +++++++++++++++++++++
 ...penGaussGlobalClockTransactionExecutorTest.java |  62 +++++++++
 4 files changed, 224 insertions(+), 11 deletions(-)

diff --git 
a/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHook.java
 
b/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHook.java
index e836c00a80b..49a040437b7 100644
--- 
a/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHook.java
+++ 
b/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHook.java
@@ -69,12 +69,13 @@ public final class GlobalClockTransactionHook implements 
TransactionHook<GlobalC
         if (!rule.getConfiguration().isEnabled()) {
             return;
         }
-        if (null == isolationLevel || TransactionIsolationLevel.READ_COMMITTED 
== isolationLevel) {
-            Optional<GlobalClockTransactionExecutor> 
globalClockTransactionExecutor = 
DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType);
-            Optional<GlobalClockProvider> globalClockProvider = 
rule.getGlobalClockProvider();
-            if (globalClockTransactionExecutor.isPresent() && 
globalClockProvider.isPresent()) {
-                
globalClockTransactionExecutor.get().sendSnapshotTimestamp(connections, 
globalClockProvider.get().getCurrentTimestamp());
-            }
+        if (null != isolationLevel && TransactionIsolationLevel.READ_COMMITTED 
!= isolationLevel) {
+            return;
+        }
+        Optional<GlobalClockTransactionExecutor> 
globalClockTransactionExecutor = 
DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType);
+        Optional<GlobalClockProvider> globalClockProvider = 
rule.getGlobalClockProvider();
+        if (globalClockTransactionExecutor.isPresent() && 
globalClockProvider.isPresent()) {
+            
globalClockTransactionExecutor.get().sendSnapshotTimestamp(connections, 
globalClockProvider.get().getCurrentTimestamp());
         }
     }
     
@@ -110,13 +111,11 @@ public final class GlobalClockTransactionHook implements 
TransactionHook<GlobalC
     }
     
     @Override
-    public void beforeRollback(final GlobalClockRule rule, final DatabaseType 
databaseType, final Collection<Connection> connections,
-                               final TransactionConnectionContext 
transactionContext) {
+    public void beforeRollback(final GlobalClockRule rule, final DatabaseType 
databaseType, final Collection<Connection> connections, final 
TransactionConnectionContext transactionContext) {
     }
     
     @Override
-    public void afterRollback(final GlobalClockRule rule, final DatabaseType 
databaseType, final Collection<Connection> connections,
-                              final TransactionConnectionContext 
transactionContext) {
+    public void afterRollback(final GlobalClockRule rule, final DatabaseType 
databaseType, final Collection<Connection> connections, final 
TransactionConnectionContext transactionContext) {
     }
     
     @Override
diff --git 
a/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutor.java
 
b/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutor.java
index 257fc64f763..16b67c9f14d 100644
--- 
a/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutor.java
+++ 
b/kernel/global-clock/core/src/main/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutor.java
@@ -25,7 +25,7 @@ import java.sql.Statement;
 import java.util.Collection;
 
 /**
- * OpenGauss global clock transaction executor.
+ * Global clock transaction executor for openGauss.
  */
 public final class OpenGaussGlobalClockTransactionExecutor implements 
GlobalClockTransactionExecutor {
     
diff --git 
a/kernel/global-clock/core/src/test/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHookTest.java
 
b/kernel/global-clock/core/src/test/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHookTest.java
new file mode 100644
index 00000000000..910050cc440
--- /dev/null
+++ 
b/kernel/global-clock/core/src/test/java/org/apache/shardingsphere/globalclock/executor/GlobalClockTransactionHookTest.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.globalclock.executor;
+
+import org.apache.shardingsphere.globalclock.provider.GlobalClockProvider;
+import org.apache.shardingsphere.globalclock.rule.GlobalClockRule;
+import 
org.apache.shardingsphere.infra.database.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import 
org.apache.shardingsphere.infra.session.connection.transaction.TransactionConnectionContext;
+import org.apache.shardingsphere.infra.spi.type.ordered.OrderedSPILoader;
+import 
org.apache.shardingsphere.sql.parser.statement.core.enums.TransactionIsolationLevel;
+import org.apache.shardingsphere.test.mock.AutoMockExtension;
+import org.apache.shardingsphere.test.mock.StaticMockSettings;
+import org.apache.shardingsphere.transaction.spi.TransactionHook;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(DatabaseTypedSPILoader.class)
+class GlobalClockTransactionHookTest {
+    
+    private GlobalClockTransactionHook transactionHook;
+    
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private GlobalClockRule rule;
+    
+    @Mock
+    private DatabaseType databaseType;
+    
+    @Mock
+    private TransactionConnectionContext transactionContext;
+    
+    @Mock
+    private GlobalClockProvider globalClockProvider;
+    
+    @Mock
+    private GlobalClockTransactionExecutor globalClockTransactionExecutor;
+    
+    @BeforeEach
+    void setUp() {
+        transactionHook = (GlobalClockTransactionHook) 
OrderedSPILoader.getServices(TransactionHook.class, 
Collections.singleton(rule)).get(rule);
+    }
+    
+    @Test
+    void assertBeforeBegin() {
+        assertDoesNotThrow(() -> transactionHook.beforeBegin(rule, 
databaseType, transactionContext));
+    }
+    
+    @Test
+    void assertAfterBeginWhenGlobalClockProviderAbsent() {
+        transactionHook.afterBegin(rule, databaseType, transactionContext);
+        verify(transactionContext, times(0)).setBeginMills(anyLong());
+    }
+    
+    @Test
+    void assertAfterBeginWhenGlobalClockProviderPresent() {
+        
when(rule.getGlobalClockProvider()).thenReturn(Optional.of(globalClockProvider));
+        when(globalClockProvider.getCurrentTimestamp()).thenReturn(10L);
+        transactionHook.afterBegin(rule, databaseType, transactionContext);
+        verify(transactionContext).setBeginMills(10L);
+    }
+    
+    @Test
+    void assertAfterCreateConnectionsWhenDisabledGlobalClockRule() throws 
SQLException {
+        transactionHook.afterCreateConnections(rule, databaseType, 
Collections.emptyList(), transactionContext);
+        verify(globalClockTransactionExecutor, 
times(0)).sendSnapshotTimestamp(any(), anyLong());
+    }
+    
+    @Test
+    void 
assertAfterCreateConnectionsWhenGlobalClockTransactionExecutorAbsent() throws 
SQLException {
+        
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType)).thenReturn(Optional.empty());
+        when(rule.getConfiguration().isEnabled()).thenReturn(true);
+        transactionHook.afterCreateConnections(rule, databaseType, 
Collections.emptyList(), transactionContext);
+        verify(globalClockTransactionExecutor, 
times(0)).sendSnapshotTimestamp(any(), anyLong());
+    }
+    
+    @Test
+    void 
assertAfterCreateConnectionsWhenGlobalClockTransactionExecutorPresent() throws 
SQLException {
+        
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType)).thenReturn(Optional.of(globalClockTransactionExecutor));
+        when(rule.getConfiguration().isEnabled()).thenReturn(true);
+        transactionHook.afterCreateConnections(rule, databaseType, 
Collections.emptyList(), transactionContext);
+        
verify(globalClockTransactionExecutor).sendSnapshotTimestamp(Collections.emptyList(),
 0L);
+    }
+    
+    @Test
+    void assertBeforeExecuteSQLWhenDisabledGlobalClockRule() throws 
SQLException {
+        transactionHook.beforeExecuteSQL(rule, databaseType, 
Collections.emptyList(), transactionContext, 
TransactionIsolationLevel.READ_COMMITTED);
+        verify(rule, times(0)).getGlobalClockProvider();
+    }
+    
+    @Test
+    void assertBeforeExecuteSQLWhenNotReadCommittedIsolationLevel() throws 
SQLException {
+        when(rule.getConfiguration().isEnabled()).thenReturn(true);
+        transactionHook.beforeExecuteSQL(rule, databaseType, 
Collections.emptyList(), transactionContext, 
TransactionIsolationLevel.REPEATABLE_READ);
+        verify(rule, times(0)).getGlobalClockProvider();
+    }
+    
+    @Test
+    void assertBeforeExecuteSQLWhenGlobalClockTransactionExecutorAbsent() 
throws SQLException {
+        when(rule.getConfiguration().isEnabled()).thenReturn(true);
+        transactionHook.beforeExecuteSQL(rule, databaseType, 
Collections.emptyList(), transactionContext, 
TransactionIsolationLevel.READ_COMMITTED);
+        
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType)).thenReturn(Optional.empty());
+        verify(globalClockTransactionExecutor, 
times(0)).sendSnapshotTimestamp(any(), anyLong());
+    }
+    
+    @Test
+    void assertBeforeExecuteSQLWhenGlobalClockProviderAbsent() throws 
SQLException {
+        when(rule.getConfiguration().isEnabled()).thenReturn(true);
+        transactionHook.beforeExecuteSQL(rule, databaseType, 
Collections.emptyList(), transactionContext, 
TransactionIsolationLevel.READ_COMMITTED);
+        
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType)).thenReturn(Optional.of(globalClockTransactionExecutor));
+        verify(globalClockTransactionExecutor, 
times(0)).sendSnapshotTimestamp(any(), anyLong());
+    }
+    
+    @Test
+    void assertBeforeExecuteSQLWhenNullTransactionIsolationLevel() throws 
SQLException {
+        when(rule.getConfiguration().isEnabled()).thenReturn(true);
+        
when(rule.getGlobalClockProvider()).thenReturn(Optional.of(globalClockProvider));
+        
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, 
databaseType)).thenReturn(Optional.of(globalClockTransactionExecutor));
+        when(globalClockProvider.getCurrentTimestamp()).thenReturn(10L);
+        transactionHook.beforeExecuteSQL(rule, databaseType, 
Collections.emptyList(), transactionContext, null);
+        
verify(globalClockTransactionExecutor).sendSnapshotTimestamp(Collections.emptyList(),
 10L);
+    }
+}
diff --git 
a/kernel/global-clock/core/src/test/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutorTest.java
 
b/kernel/global-clock/core/src/test/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutorTest.java
new file mode 100644
index 00000000000..4873ce78cf0
--- /dev/null
+++ 
b/kernel/global-clock/core/src/test/java/org/apache/shardingsphere/globalclock/executor/type/OpenGaussGlobalClockTransactionExecutorTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.globalclock.executor.type;
+
+import 
org.apache.shardingsphere.globalclock.executor.GlobalClockTransactionExecutor;
+import 
org.apache.shardingsphere.infra.database.core.spi.DatabaseTypedSPILoader;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collections;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class OpenGaussGlobalClockTransactionExecutorTest {
+    
+    private GlobalClockTransactionExecutor executor;
+    
+    @BeforeEach
+    void setUp() {
+        executor = 
DatabaseTypedSPILoader.getService(GlobalClockTransactionExecutor.class, 
TypedSPILoader.getService(DatabaseType.class, "openGauss"));
+    }
+    
+    @Test
+    void assertSendSnapshotTimestamp() throws SQLException {
+        Connection connection = mock(Connection.class);
+        Statement statement = mock(Statement.class);
+        when(connection.createStatement()).thenReturn(statement);
+        executor.sendSnapshotTimestamp(Collections.singleton(connection), 10L);
+        verify(statement).execute("SELECT 10 AS SETSNAPSHOTCSN");
+    }
+    
+    @Test
+    void assertSendCommitTimestamp() throws SQLException {
+        Connection connection = mock(Connection.class);
+        Statement statement = mock(Statement.class);
+        when(connection.createStatement()).thenReturn(statement);
+        executor.sendCommitTimestamp(Collections.singleton(connection), 10L);
+        verify(statement).execute("SELECT 10 AS SETCOMMITCSN");
+    }
+}

Reply via email to