Skip to content

Commit

Permalink
Add test cases on GlobalClockTransactionHook (apache#32948)
Browse files Browse the repository at this point in the history
* Add test cases on GlobalClockTransactionHook

* Add test cases on GlobalClockTransactionHook
  • Loading branch information
terrymanu authored Sep 21, 2024
1 parent 68e4359 commit d06f8fa
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 16 deletions.
6 changes: 6 additions & 0 deletions kernel/global-clock/core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-test-util</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-test-it-yaml</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.apache.shardingsphere.globalclock.executor;

import com.google.common.base.Preconditions;
import org.apache.shardingsphere.globalclock.provider.GlobalClockProvider;
import org.apache.shardingsphere.globalclock.rule.GlobalClockRule;
import org.apache.shardingsphere.globalclock.rule.constant.GlobalClockOrder;
Expand Down Expand Up @@ -66,17 +67,16 @@ public void afterCreateConnections(final GlobalClockRule rule, final DatabaseTyp
@Override
public void beforeExecuteSQL(final GlobalClockRule rule, final DatabaseType databaseType, final Collection<Connection> connections, final TransactionConnectionContext connectionContext,
final TransactionIsolationLevel isolationLevel) throws SQLException {
if (!rule.getConfiguration().isEnabled()) {
if (!rule.getConfiguration().isEnabled() || null != isolationLevel && TransactionIsolationLevel.READ_COMMITTED != isolationLevel) {
return;
}
if (null != isolationLevel && TransactionIsolationLevel.READ_COMMITTED != isolationLevel) {
Optional<GlobalClockTransactionExecutor> globalClockTransactionExecutor = DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, databaseType);
if (!globalClockTransactionExecutor.isPresent()) {
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());
}
Preconditions.checkState(globalClockProvider.isPresent());
globalClockTransactionExecutor.get().sendSnapshotTimestamp(connections, globalClockProvider.get().getCurrentTimestamp());
}

@Override
Expand All @@ -88,10 +88,12 @@ public void beforeCommit(final GlobalClockRule rule, final DatabaseType database
}
if (lockContext.tryLock(lockDefinition, 200L)) {
Optional<GlobalClockTransactionExecutor> globalClockTransactionExecutor = DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, databaseType);
Optional<GlobalClockProvider> globalClockProvider = rule.getGlobalClockProvider();
if (globalClockTransactionExecutor.isPresent() && globalClockProvider.isPresent()) {
globalClockTransactionExecutor.get().sendCommitTimestamp(connections, globalClockProvider.get().getCurrentTimestamp());
if (!globalClockTransactionExecutor.isPresent()) {
return;
}
Optional<GlobalClockProvider> globalClockProvider = rule.getGlobalClockProvider();
Preconditions.checkState(globalClockProvider.isPresent());
globalClockTransactionExecutor.get().sendCommitTimestamp(connections, globalClockProvider.get().getCurrentTimestamp());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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.lock.LockContext;
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;
Expand All @@ -40,6 +41,7 @@
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.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -127,26 +129,83 @@ void assertBeforeExecuteSQLWhenNotReadCommittedIsolationLevel() throws SQLExcept
@Test
void assertBeforeExecuteSQLWhenGlobalClockTransactionExecutorAbsent() throws SQLException {
when(rule.getConfiguration().isEnabled()).thenReturn(true);
when(rule.getGlobalClockProvider()).thenReturn(Optional.of(globalClockProvider));
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 {
void assertBeforeExecuteSQLWhenNullTransactionIsolationLevel() throws SQLException {
when(rule.getConfiguration().isEnabled()).thenReturn(true);
transactionHook.beforeExecuteSQL(rule, databaseType, Collections.emptyList(), transactionContext, TransactionIsolationLevel.READ_COMMITTED);
when(rule.getGlobalClockProvider()).thenReturn(Optional.of(globalClockProvider));
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, databaseType)).thenReturn(Optional.of(globalClockTransactionExecutor));
verify(globalClockTransactionExecutor, times(0)).sendSnapshotTimestamp(any(), anyLong());
when(globalClockProvider.getCurrentTimestamp()).thenReturn(10L);
transactionHook.beforeExecuteSQL(rule, databaseType, Collections.emptyList(), transactionContext, null);
verify(globalClockTransactionExecutor).sendSnapshotTimestamp(Collections.emptyList(), 10L);
}

@SuppressWarnings({"rawtypes", "unchecked"})
@Test
void assertBeforeExecuteSQLWhenNullTransactionIsolationLevel() throws SQLException {
void assertBeforeCommitWhenDisabledGlobalClockRule() throws SQLException {
LockContext lockContext = mock(LockContext.class);
transactionHook.beforeCommit(rule, databaseType, Collections.emptyList(), transactionContext, lockContext);
verify(lockContext, times(0)).tryLock(any(), anyLong());
}

@SuppressWarnings("rawtypes")
@Test
void assertBeforeCommitWhenTryLockFailed() throws SQLException {
when(rule.getConfiguration().isEnabled()).thenReturn(true);
LockContext lockContext = mock(LockContext.class);
transactionHook.beforeCommit(rule, databaseType, Collections.emptyList(), transactionContext, lockContext);
verify(globalClockTransactionExecutor, times(0)).sendCommitTimestamp(any(), anyLong());
}

@SuppressWarnings({"rawtypes", "unchecked"})
@Test
void assertBeforeCommitWhenGlobalClockTransactionExecutorAbsent() throws SQLException {
when(rule.getConfiguration().isEnabled()).thenReturn(true);
LockContext lockContext = mock(LockContext.class);
when(lockContext.tryLock(any(), anyLong())).thenReturn(true);
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, databaseType)).thenReturn(Optional.empty());
transactionHook.beforeCommit(rule, databaseType, Collections.emptyList(), transactionContext, lockContext);
verify(globalClockTransactionExecutor, times(0)).sendCommitTimestamp(any(), anyLong());
}

@SuppressWarnings({"rawtypes", "unchecked"})
@Test
void assertBeforeCommit() 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);
LockContext lockContext = mock(LockContext.class);
when(lockContext.tryLock(any(), anyLong())).thenReturn(true);
when(DatabaseTypedSPILoader.findService(GlobalClockTransactionExecutor.class, databaseType)).thenReturn(Optional.of(globalClockTransactionExecutor));
transactionHook.beforeCommit(rule, databaseType, Collections.emptyList(), transactionContext, lockContext);
verify(globalClockTransactionExecutor).sendCommitTimestamp(Collections.emptyList(), 10L);
}

@Test
void assertAfterCommitWhenGlobalClockProviderAbsent() {
transactionHook.afterCommit(rule, databaseType, Collections.emptyList(), transactionContext, mock(LockContext.class));
verify(globalClockProvider, times(0)).getNextTimestamp();
}

@Test
void assertAfterCommitWhenGlobalClockProviderPresent() {
when(rule.getGlobalClockProvider()).thenReturn(Optional.of(globalClockProvider));
transactionHook.afterCommit(rule, databaseType, Collections.emptyList(), transactionContext, mock(LockContext.class));
verify(globalClockProvider).getNextTimestamp();
}

@Test
void assertBeforeRollback() {
assertDoesNotThrow(() -> transactionHook.beforeRollback(rule, databaseType, Collections.emptyList(), transactionContext));
}

@Test
void assertAfterRollback() {
assertDoesNotThrow(() -> transactionHook.afterRollback(rule, databaseType, Collections.emptyList(), transactionContext));
}
}

0 comments on commit d06f8fa

Please sign in to comment.