This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new 9998778ed8 test: improve test coverage for rm-datasource (#7788)
9998778ed8 is described below
commit 9998778ed80e8bc8d898ec60c759d86cd06fb3b4
Author: Eric Wang <[email protected]>
AuthorDate: Wed Nov 19 11:29:21 2025 +0300
test: improve test coverage for rm-datasource (#7788)
---
changes/en-us/2.x.md | 7 +
changes/zh-cn/2.x.md | 8 +-
.../MySQLInsertOnDuplicateUpdateExecutor.java | 3 +-
.../sql/struct/cache/AbstractTableMetaCache.java | 13 +-
.../seata/rm/datasource/ConnectionProxyTest.java | 707 ++++++++++++++++++++-
...MariadbInsertOnDuplicateUpdateExecutorTest.java | 2 -
.../MySQLInsertOnDuplicateUpdateExecutorTest.java | 562 +++++++++++++++-
...olarDBXInsertOnDuplicateUpdateExecutorTest.java | 2 -
.../struct/cache/KingbaseTableMetaCacheTest.java | 335 ++++++++++
.../sql/struct/cache/OracleTableMetaCacheTest.java | 269 ++++++++
...CacheTest.java => OscarTableMetaCacheTest.java} | 53 +-
.../seata/rm/datasource/util/JdbcUtilsTest.java | 266 ++++++++
12 files changed, 2182 insertions(+), 45 deletions(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index aab175dbe3..5e511e0a3a 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -105,6 +105,13 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#7757](https://github.com/apache/incubator-seata/pull/7757)] add UT for
undo module
- [[#7763](https://github.com/apache/incubator-seata/pull/7763)] add UT for
RegistryNamingServerProperties and RegistryMetadataProperties
- [[#7764](https://github.com/apache/incubator-seata/pull/7764)] add some UT
for server/coordinator module
+- [[#7788](https://github.com/apache/incubator-seata/pull/7788)] add some UT
for rm-datasource module
+- [[#7774](https://github.com/apache/incubator-seata/pull/7774)] add some UT
for server/console module
+- [[#7767](https://github.com/apache/incubator-seata/pull/7767)] add some UT
for server/cluster module
+- [[#7750](https://github.com/apache/incubator-seata/pull/7750)] add some UT
for server module
+- [[#7733](https://github.com/apache/incubator-seata/pull/7733)] add some UT
for core module
+- [[#7728](https://github.com/apache/incubator-seata/pull/7728)] add some UT
for compatible module
+- [[#7727](https://github.com/apache/incubator-seata/pull/7727)] add some UT
for compatible module
### refactor:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 3774714a66..112388d45e 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -104,7 +104,13 @@
- [[#7757](https://github.com/apache/incubator-seata/pull/7757)] 为 undo 模块添加单测
- [[#7763](https://github.com/apache/incubator-seata/pull/7763)] 为
RegistryNamingServerProperties 和 RegistryMetadataProperties 添加单测
- [[#7764](https://github.com/apache/incubator-seata/pull/7764)] 为
server/coordinator 模块添加单测
-
+- [[#7788](https://github.com/apache/incubator-seata/pull/7788)] 为
rm-datasource 模块添加单测
+- [[#7774](https://github.com/apache/incubator-seata/pull/7774)] 为
server/console 模块添加单测
+- [[#7767](https://github.com/apache/incubator-seata/pull/7767)] 为
server/cluster 模块添加单测
+- [[#7750](https://github.com/apache/incubator-seata/pull/7750)] 为 server
模块添加单测
+- [[#7733](https://github.com/apache/incubator-seata/pull/7733)] 为 core 模块添加单测
+- [[#7728](https://github.com/apache/incubator-seata/pull/7728)] 为 compatible
模块添加单测
+- [[#7727](https://github.com/apache/incubator-seata/pull/7727)] 为 compatible
模块添加单测
### refactor:
- [[#7615](https://github.com/seata/seata/pull/7615)] 重构 DataSourceProxy
diff --git
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/mysql/MySQLInsertOnDuplicateUpdateExecutor.java
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/mysql/MySQLInsertOnDuplicateUpdateExecutor.java
index 53bc05831d..5c3b2533b1 100644
---
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/mysql/MySQLInsertOnDuplicateUpdateExecutor.java
+++
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/exec/mysql/MySQLInsertOnDuplicateUpdateExecutor.java
@@ -365,7 +365,8 @@ public class MySQLInsertOnDuplicateUpdateExecutor extends
MySQLInsertExecutor im
}
}
StringJoiner selectSQLJoin = new StringJoiner(", ", prefix,
suffix.toString());
- return selectSQLJoin.toString();
+ selectSQL = selectSQLJoin.toString();
+ return selectSQL;
}
/**
diff --git
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/AbstractTableMetaCache.java
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/AbstractTableMetaCache.java
index 3caac9e4e9..eff2a9ba05 100755
---
a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/AbstractTableMetaCache.java
+++
b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/sql/struct/cache/AbstractTableMetaCache.java
@@ -87,13 +87,16 @@ public abstract class AbstractTableMetaCache implements
TableMetaCache {
public void refresh(final Connection connection, String resourceId) {
ConcurrentMap<String, TableMeta> tableMetaMap =
TABLE_META_CACHE.asMap();
for (Map.Entry<String, TableMeta> entry : tableMetaMap.entrySet()) {
- String key = getCacheKey(connection,
entry.getValue().getOriginalTableName(), resourceId);
+ TableMeta meta = entry.getValue();
+ String tableNameForKey =
StringUtils.isBlank(meta.getOriginalTableName())
+ ? meta.getTableName()
+ : meta.getOriginalTableName();
+
+ String key = getCacheKey(connection, tableNameForKey, resourceId);
if (entry.getKey().equals(key)) {
try {
- String freshTableName =
StringUtils.isBlank(entry.getValue().getOriginalTableName())
- ? entry.getValue().getTableName()
- : entry.getValue().getOriginalTableName();
- TableMeta tableMeta = fetchSchema(connection,
freshTableName);
+ // Reuse tableNameForKey directly, no need to check again
+ TableMeta tableMeta = fetchSchema(connection,
tableNameForKey);
if (!tableMeta.equals(entry.getValue())) {
TABLE_META_CACHE.put(entry.getKey(), tableMeta);
LOGGER.info("table meta change was found, update table
meta cache automatically.");
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/ConnectionProxyTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/ConnectionProxyTest.java
index 415028e175..6f82a14c32 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/ConnectionProxyTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/ConnectionProxyTest.java
@@ -20,10 +20,12 @@ import org.apache.seata.common.LockStrategyMode;
import org.apache.seata.core.context.GlobalLockConfigHolder;
import org.apache.seata.core.exception.TransactionException;
import org.apache.seata.core.exception.TransactionExceptionCode;
+import org.apache.seata.core.model.BranchStatus;
import org.apache.seata.core.model.BranchType;
import org.apache.seata.core.model.GlobalLockConfig;
import org.apache.seata.rm.DefaultResourceManager;
import org.apache.seata.rm.datasource.ConnectionProxy.LockRetryPolicy;
+import org.apache.seata.rm.datasource.exec.LockConflictException;
import org.apache.seata.rm.datasource.exec.LockWaitTimeoutException;
import org.apache.seata.rm.datasource.mock.MockConnection;
import org.apache.seata.rm.datasource.mock.MockDriver;
@@ -39,6 +41,8 @@ import org.mockito.Mockito;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.sql.SQLException;
+import java.sql.Savepoint;
/**
* ConnectionProxy test
@@ -58,6 +62,7 @@ public class ConnectionProxyTest {
private static final String DB_TYPE = "mysql";
private Field branchRollbackFlagField;
+ private boolean originalBranchRollbackFlag;
@BeforeEach
public void initBeforeEach() throws Exception {
@@ -67,8 +72,7 @@ public class ConnectionProxyTest {
modifiersField.setAccessible(true);
modifiersField.setInt(branchRollbackFlagField,
branchRollbackFlagField.getModifiers() & ~Modifier.FINAL);
branchRollbackFlagField.setAccessible(true);
- boolean branchRollbackFlag = (boolean)
branchRollbackFlagField.get(null);
- Assertions.assertTrue(branchRollbackFlag);
+ originalBranchRollbackFlag = (boolean)
branchRollbackFlagField.get(null);
dataSourceProxy = Mockito.mock(DataSourceProxy.class);
Mockito.when(dataSourceProxy.getResourceId()).thenReturn(TEST_RESOURCE_ID);
@@ -88,32 +92,35 @@ public class ConnectionProxyTest {
DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
}
+ @org.junit.jupiter.api.AfterEach
+ public void cleanupAfterEach() throws Exception {
+ branchRollbackFlagField.set(null, originalBranchRollbackFlag);
+ }
+
@Test
public void testLockRetryPolicyRollbackOnConflict() throws Exception {
- boolean oldBranchRollbackFlag = (boolean)
branchRollbackFlagField.get(null);
branchRollbackFlagField.set(null, true);
GlobalLockConfig preGlobalLockConfig = new GlobalLockConfig();
preGlobalLockConfig.setLockRetryTimes(0);
preGlobalLockConfig.setLockRetryInterval(10);
preGlobalLockConfig.setLockStrategyMode(LockStrategyMode.PESSIMISTIC);
GlobalLockConfig globalLockConfig =
GlobalLockConfigHolder.setAndReturnPrevious(preGlobalLockConfig);
- ConnectionProxy connectionProxy =
- new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null));
- connectionProxy.bind(TEST_XID);
- SQLUndoLog sqlUndoLog = new SQLUndoLog();
- TableRecords beforeImage = new TableRecords();
- beforeImage.add(new Row());
- sqlUndoLog.setBeforeImage(beforeImage);
- connectionProxy.getContext().appendUndoItem(sqlUndoLog);
- connectionProxy.appendUndoLog(new SQLUndoLog());
- connectionProxy.appendLockKey(lockKey);
- Assertions.assertThrows(LockWaitTimeoutException.class,
connectionProxy::commit);
- branchRollbackFlagField.set(null, oldBranchRollbackFlag);
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.getContext().appendUndoItem(sqlUndoLog);
+ connectionProxy.appendUndoLog(new SQLUndoLog());
+ connectionProxy.appendLockKey(lockKey);
+ Assertions.assertThrows(LockWaitTimeoutException.class,
connectionProxy::commit);
+ }
}
@Test
public void testLockRetryPolicyNotRollbackOnConflict() throws Exception {
- boolean oldBranchRollbackFlag = (boolean)
branchRollbackFlagField.get(null);
branchRollbackFlagField.set(null, false);
GlobalLockConfig preGlobalLockConfig = new GlobalLockConfig();
preGlobalLockConfig.setLockRetryTimes(30);
@@ -130,6 +137,672 @@ public class ConnectionProxyTest {
sqlUndoLog.setBeforeImage(beforeImage);
connectionProxy.getContext().appendUndoItem(sqlUndoLog);
Assertions.assertThrows(LockWaitTimeoutException.class,
connectionProxy::commit);
- branchRollbackFlagField.set(null, oldBranchRollbackFlag);
+ }
+
+ @Test
+ public void testGetContext() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ Assertions.assertNotNull(connectionProxy.getContext());
+ }
+ }
+
+ @Test
+ public void testBindXid() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ connectionProxy.bind(TEST_XID);
+ Assertions.assertEquals(TEST_XID,
connectionProxy.getContext().getXid());
+ }
+ }
+
+ @Test
+ public void testSetGlobalLockRequire() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ connectionProxy.setGlobalLockRequire(true);
+ Assertions.assertTrue(connectionProxy.isGlobalLockRequire());
+ connectionProxy.setGlobalLockRequire(false);
+ Assertions.assertFalse(connectionProxy.isGlobalLockRequire());
+ }
+ }
+
+ @Test
+ public void testAppendUndoLog() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ SQLUndoLog undoLog = new SQLUndoLog();
+ connectionProxy.appendUndoLog(undoLog);
+ Assertions.assertEquals(
+ 1, connectionProxy.getContext().getUndoItems().size());
+ }
+ }
+
+ @Test
+ public void testAppendLockKey() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ connectionProxy.appendLockKey("test:1");
+ connectionProxy.appendLockKey("test:2");
+ Assertions.assertNotNull(connectionProxy.getContext());
+ }
+ }
+
+ @Test
+ public void testGetTargetConnection() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ Assertions.assertEquals(mockConnection,
connectionProxy.getTargetConnection());
+ }
+ }
+
+ @Test
+ public void testGetDataSourceProxy() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ Assertions.assertEquals(dataSourceProxy,
connectionProxy.getDataSourceProxy());
+ }
+ }
+
+ @Test
+ public void testCheckLockWithBlankLockKeys() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ connectionProxy.bind(TEST_XID);
+ connectionProxy.checkLock("");
+ connectionProxy.checkLock(null);
+ }
+ }
+
+ @Test
+ public void testLockQueryWithBlankLockKeys() throws Exception {
+ try (ConnectionProxy connectionProxy =
+ new ConnectionProxy(dataSourceProxy, new MockConnection(new
MockDriver(), "", null))) {
+ connectionProxy.bind(TEST_XID);
+ boolean result = connectionProxy.lockQuery("");
+ Assertions.assertFalse(result);
+ }
+ }
+
+ @Test
+ public void commitInGlobalTransactionTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString()))
+ .thenReturn(123456L);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ Mockito.verify(rm)
+ .branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.eq(TEST_XID),
+ Mockito.anyString(),
+ Mockito.eq(lockKey));
+ }
+ }
+
+ @Test
+ public void commitWithGlobalLockRequireTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT), Mockito.anyString(),
Mockito.isNull(), Mockito.anyString()))
+ .thenReturn(true);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.setGlobalLockRequire(true);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ Mockito.verify(rm)
+ .lockQuery(Mockito.eq(BranchType.AT), Mockito.anyString(),
Mockito.isNull(), Mockito.eq(lockKey));
+ }
+ }
+
+ @Test
+ public void commitWithoutTransactionTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ connectionProxy.setAutoCommit(false);
+
+ connectionProxy.commit();
+
+ Assertions.assertNull(connectionProxy.getContext().getXid());
+ }
+ }
+
+ @Test
+ public void commitWithSQLExceptionTest() throws Exception {
+ MockConnection mockConnection = Mockito.mock(MockConnection.class);
+ Mockito.when(mockConnection.getAutoCommit()).thenReturn(false);
+ Mockito.doThrow(new SQLException("Commit
failed")).when(mockConnection).commit();
+ Mockito.doNothing().when(mockConnection).rollback();
+
+ ConnectionProxy connectionProxy = new ConnectionProxy(dataSourceProxy,
mockConnection);
+ connectionProxy.setAutoCommit(false);
+
+ Assertions.assertThrows(SQLException.class, connectionProxy::commit);
+
+ Mockito.verify(mockConnection).rollback();
+ }
+
+ @Test
+ public void rollbackTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ connectionProxy.setAutoCommit(false);
+
+ connectionProxy.rollback();
+
+ Assertions.assertNull(connectionProxy.getContext().getBranchId());
+ }
+ }
+
+ @Test
+ public void rollbackWithBranchRegisteredTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString()))
+ .thenReturn(123456L);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ connectionProxy.bind(TEST_XID);
+ connectionProxy.getContext().setBranchId(123456L);
+ connectionProxy.rollback();
+
+ Mockito.verify(rm)
+ .branchReport(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(123456L),
+ Mockito.eq(BranchStatus.PhaseOne_Failed),
+ Mockito.isNull());
+ }
+ }
+
+ @Test
+ public void registerSuccessTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.isNull(),
+ Mockito.eq(TEST_XID),
+ Mockito.anyString(),
+ Mockito.eq(lockKey)))
+ .thenReturn(789L);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ Mockito.verify(rm)
+ .branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.isNull(),
+ Mockito.eq(TEST_XID),
+ Mockito.anyString(),
+ Mockito.eq(lockKey));
+ }
+ }
+
+ @Test
+ public void registerWithNoUndoLogTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ Mockito.verify(rm, Mockito.never())
+ .branchRegister(
+ Mockito.any(),
+ Mockito.anyString(),
+ Mockito.any(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString());
+ }
+ }
+
+ @Test
+ public void registerWithNoLockKeyTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+
+ connectionProxy.commit();
+
+ Mockito.verify(rm, Mockito.never())
+ .branchRegister(
+ Mockito.any(),
+ Mockito.anyString(),
+ Mockito.any(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString());
+ }
+ }
+
+ @Test
+ public void reportSuccessTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString()))
+ .thenReturn(999L);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ if (ConnectionProxy.IS_REPORT_SUCCESS_ENABLE) {
+ Mockito.verify(rm)
+ .branchReport(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(999L),
+ Mockito.eq(BranchStatus.PhaseOne_Done),
+ Mockito.isNull());
+ }
+ }
+ }
+
+ @Test
+ public void reportFailureTest() throws Exception {
+ MockConnection mockConnection = Mockito.mock(MockConnection.class);
+ Mockito.when(mockConnection.getAutoCommit()).thenReturn(false);
+ Mockito.doThrow(new SQLException("Commit
failed")).when(mockConnection).commit();
+
+ ConnectionProxy connectionProxy = new ConnectionProxy(dataSourceProxy,
mockConnection);
+
+ DefaultResourceManager rm = Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString()))
+ .thenReturn(888L);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ Assertions.assertThrows(SQLException.class, connectionProxy::commit);
+
+ Mockito.verify(rm, Mockito.times(2))
+ .branchReport(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(888L),
+ Mockito.eq(BranchStatus.PhaseOne_Failed),
+ Mockito.isNull());
+ }
+
+ @Test
+ public void reportWithRetryTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString()))
+ .thenReturn(777L);
+ Mockito.doThrow(new TransactionException("Report failed"))
+ .doNothing()
+ .when(rm)
+ .branchReport(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(777L),
+ Mockito.eq(BranchStatus.PhaseOne_Done),
+ Mockito.isNull());
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.commit();
+
+ if (ConnectionProxy.IS_REPORT_SUCCESS_ENABLE) {
+ Mockito.verify(rm, Mockito.atLeast(1))
+ .branchReport(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(777L),
+ Mockito.eq(BranchStatus.PhaseOne_Done),
+ Mockito.isNull());
+ }
+ }
+ }
+
+ @Test
+ public void setAutoCommitToTrueInGlobalTransactionTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.anyString(),
+ Mockito.anyString(),
+ Mockito.anyString()))
+ .thenReturn(555L);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.bind(TEST_XID);
+ SQLUndoLog sqlUndoLog = new SQLUndoLog();
+ TableRecords beforeImage = new TableRecords();
+ beforeImage.add(new Row());
+ sqlUndoLog.setBeforeImage(beforeImage);
+ connectionProxy.appendUndoLog(sqlUndoLog);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.setAutoCommit(true);
+
+ Mockito.verify(rm)
+ .branchRegister(
+ Mockito.eq(BranchType.AT),
+ Mockito.anyString(),
+ Mockito.isNull(),
+ Mockito.eq(TEST_XID),
+ Mockito.anyString(),
+ Mockito.eq(lockKey));
+ Assertions.assertTrue(mockConnection.getAutoCommit());
+ }
+ }
+
+ @Test
+ public void setAutoCommitToTrueWithGlobalLockTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT), Mockito.anyString(),
Mockito.isNull(), Mockito.anyString()))
+ .thenReturn(true);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.setAutoCommit(false);
+ connectionProxy.setGlobalLockRequire(true);
+ connectionProxy.appendLockKey(lockKey);
+
+ connectionProxy.setAutoCommit(true);
+
+ Mockito.verify(rm)
+ .lockQuery(Mockito.eq(BranchType.AT), Mockito.anyString(),
Mockito.isNull(), Mockito.eq(lockKey));
+ Assertions.assertTrue(mockConnection.getAutoCommit());
+ }
+ }
+
+ @Test
+ public void checkLockWithRealLockKeysTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey)))
+ .thenReturn(true);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.bind(TEST_XID);
+
+ connectionProxy.checkLock(lockKey);
+
+ Mockito.verify(rm)
+ .lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey));
+ }
+ }
+
+ @Test
+ public void checkLockWithConflictTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey)))
+ .thenReturn(false);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.bind(TEST_XID);
+
+ Assertions.assertThrows(LockConflictException.class, () ->
connectionProxy.checkLock(lockKey));
+ }
+ }
+
+ @Test
+ public void lockQueryReturnsTrueTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey)))
+ .thenReturn(true);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.bind(TEST_XID);
+
+ boolean result = connectionProxy.lockQuery(lockKey);
+
+ Assertions.assertTrue(result);
+ }
+ }
+
+ @Test
+ public void lockQueryReturnsFalseTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey)))
+ .thenReturn(false);
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.bind(TEST_XID);
+
+ boolean result = connectionProxy.lockQuery(lockKey);
+
+ Assertions.assertFalse(result);
+ }
+ }
+
+ @Test
+ public void setSavepointTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ Savepoint savepoint = connectionProxy.setSavepoint();
+
+ Assertions.assertNotNull(savepoint);
+ }
+ }
+
+ @Test
+ public void setSavepointWithNameTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ String savepointName = "sp1";
+ Savepoint savepoint = connectionProxy.setSavepoint(savepointName);
+
+ Assertions.assertNotNull(savepoint);
+ }
+ }
+
+ @Test
+ public void rollbackToSavepointTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ Savepoint savepoint = connectionProxy.setSavepoint();
+ Assertions.assertNotNull(savepoint);
+
+ connectionProxy.rollback(savepoint);
+
+ Assertions.assertNotNull(connectionProxy.getContext());
+ }
+ }
+
+ @Test
+ public void releaseSavepointTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ Savepoint savepoint = connectionProxy.setSavepoint();
+ Assertions.assertNotNull(savepoint);
+
+ connectionProxy.releaseSavepoint(savepoint);
+
+ Assertions.assertNotNull(connectionProxy.getContext());
+ }
+ }
+
+ @Test
+ public void recognizeLockKeyConflictExceptionTest() throws Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey)))
+ .thenThrow(new
TransactionException(TransactionExceptionCode.LockKeyConflict, "lock
conflict"));
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.bind(TEST_XID);
+
+ LockConflictException exception =
+ Assertions.assertThrows(LockConflictException.class, () ->
connectionProxy.checkLock(lockKey));
+ Assertions.assertEquals(TransactionExceptionCode.LockKeyConflict,
exception.getCode());
+ }
+ }
+
+ @Test
+ public void recognizeLockKeyConflictFailFastExceptionTest() throws
Exception {
+ MockConnection mockConnection = new MockConnection(new MockDriver(),
"", null);
+ try (ConnectionProxy connectionProxy = new
ConnectionProxy(dataSourceProxy, mockConnection)) {
+ DefaultResourceManager rm =
Mockito.mock(DefaultResourceManager.class);
+ Mockito.when(rm.lockQuery(
+ Mockito.eq(BranchType.AT),
+ Mockito.eq(TEST_RESOURCE_ID),
+ Mockito.eq(TEST_XID),
+ Mockito.eq(lockKey)))
+ .thenThrow(new TransactionException(
+ TransactionExceptionCode.LockKeyConflictFailFast,
"lock conflict fail fast"));
+ DefaultResourceManager.mockResourceManager(BranchType.AT, rm);
+
+ connectionProxy.bind(TEST_XID);
+
+ LockConflictException exception =
+ Assertions.assertThrows(LockConflictException.class, () ->
connectionProxy.checkLock(lockKey));
+
Assertions.assertEquals(TransactionExceptionCode.LockKeyConflictFailFast,
exception.getCode());
+ }
}
}
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java
index c0048bc84e..f64866d69f 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MariadbInsertOnDuplicateUpdateExecutorTest.java
@@ -43,8 +43,6 @@ import static org.mockito.Mockito.when;
public class MariadbInsertOnDuplicateUpdateExecutorTest extends
MySQLInsertOnDuplicateUpdateExecutorTest {
- protected MariadbInsertOnDuplicateUpdateExecutor insertOrUpdateExecutor;
-
@BeforeEach
@Override
public void init() {
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java
index b18044beef..3d5919801b 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/MySQLInsertOnDuplicateUpdateExecutorTest.java
@@ -18,12 +18,19 @@ package org.apache.seata.rm.datasource.exec;
import com.google.common.collect.Lists;
import org.apache.seata.common.exception.NotSupportYetException;
+import org.apache.seata.common.exception.ShouldNeverHappenException;
+import org.apache.seata.common.util.LowerCaseLinkHashMap;
import org.apache.seata.rm.datasource.ConnectionProxy;
import org.apache.seata.rm.datasource.PreparedStatementProxy;
import org.apache.seata.rm.datasource.StatementProxy;
import
org.apache.seata.rm.datasource.exec.mysql.MySQLInsertOnDuplicateUpdateExecutor;
+import org.apache.seata.rm.datasource.sql.struct.Field;
+import org.apache.seata.rm.datasource.sql.struct.KeyType;
+import org.apache.seata.rm.datasource.sql.struct.Row;
import org.apache.seata.rm.datasource.sql.struct.TableRecords;
+import org.apache.seata.rm.datasource.undo.SQLUndoLog;
import org.apache.seata.sqlparser.SQLInsertRecognizer;
+import org.apache.seata.sqlparser.SQLType;
import org.apache.seata.sqlparser.struct.ColumnMeta;
import org.apache.seata.sqlparser.struct.IndexMeta;
import org.apache.seata.sqlparser.struct.IndexType;
@@ -34,6 +41,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
+import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -43,8 +51,12 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class MySQLInsertOnDuplicateUpdateExecutorTest {
@@ -171,21 +183,150 @@ public class MySQLInsertOnDuplicateUpdateExecutorTest {
});
}
- protected void mockAllIndexes() {
+ @Test
+ public void testBuildImageParametersWithUpdatePrimaryKey() {
+ mockParameters();
+ mockInsertColumns();
+ List<String> duplicateKeyUpdateColumns = new ArrayList<>();
+ duplicateKeyUpdateColumns.add("id");
+
when(sqlInsertRecognizer.getDuplicateKeyUpdate()).thenReturn(duplicateKeyUpdateColumns);
+
+ mockAllIndexes();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+
+ List<List<Object>> rows = new ArrayList<>();
+ rows.add(Arrays.asList("?", "?", "?", "?"));
+
when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(rows);
+
+ Assertions.assertThrows(ShouldNeverHappenException.class, () -> {
+ insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer);
+ });
+ }
+
+ @Test
+ public void testBuildImageParametersWithEmptyInsertColumns() {
+ mockParameters();
+ when(sqlInsertRecognizer.getInsertColumns()).thenReturn(null);
+
+ Map<String, ColumnMeta> allColumns = new LinkedHashMap<>();
+ allColumns.put("id", new ColumnMeta());
+ allColumns.put("user_id", new ColumnMeta());
+ allColumns.put("user_name", new ColumnMeta());
+ allColumns.put("user_status", new ColumnMeta());
+ when(tableMeta.getAllColumns()).thenReturn(allColumns);
+
+ List<List<Object>> rows = new ArrayList<>();
+ rows.add(Arrays.asList("?", "?", "?", "?"));
+
when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(rows);
+
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+
+ Map<String, ArrayList<Object>> result =
insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer);
+ Assertions.assertNotNull(result);
+ }
+
+ @Test
+ public void testBuildImageSQLWithDefaultValue() {
+ mockParametersWithoutPkColumn();
+ List<String> columns = new ArrayList<>();
+ columns.add(USER_ID_COLUMN);
+ columns.add(USER_NAME_COLUMN);
+ columns.add(USER_STATUS_COLUMN);
+ when(sqlInsertRecognizer.getInsertColumns()).thenReturn(columns);
+ Map<String, Integer> pkIndexWithoutId = new HashMap<>();
+ doReturn(pkIndexWithoutId).when(insertOrUpdateExecutor).getPkIndex();
+
Map<String, IndexMeta> allIndex = new HashMap<>();
IndexMeta primary = new IndexMeta();
primary.setIndextype(IndexType.PRIMARY);
ColumnMeta columnMeta = new ColumnMeta();
columnMeta.setColumnName("id");
+ columnMeta.setColumnDef("AUTO_INCREMENT");
primary.setValues(Lists.newArrayList(columnMeta));
- allIndex.put("id", primary);
+ allIndex.put("PRIMARY", primary);
+ when(tableMeta.getAllIndexes()).thenReturn(allIndex);
+
+ List<List<Object>> insertRows = new ArrayList<>();
+ insertRows.add(Arrays.asList("?", "?", "?"));
+
when(sqlInsertRecognizer.getInsertRows(pkIndexWithoutId.values())).thenReturn(insertRows);
+
+ String sql = insertOrUpdateExecutor.buildImageSQL(tableMeta);
+ Assertions.assertTrue(sql.contains("DEFAULT"));
+ }
+
+ @Test
+ public void testBuildTableRecords2WithEmptyParamAppenderList() {
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+
+ Assertions.assertThrows(NotSupportYetException.class, () -> {
+ insertOrUpdateExecutor.buildTableRecords2(
+ tableMeta, "SELECT * FROM test", new ArrayList<>(),
Collections.emptyList());
+ });
+ }
+
+ @Test
+ public void testBuildImageParametersWithRowSizeMismatch() {
+ mockParameters();
+ mockInsertColumns();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ List<List<Object>> rows = new ArrayList<>();
+ rows.add(Arrays.asList("?", "?"));
+
when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(rows);
+
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ insertOrUpdateExecutor.buildImageParameters(sqlInsertRecognizer);
+ });
+ }
+
+ @Test
+ public void testGetSelectSQL() {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+
+ List<List<Object>> insertRows = new ArrayList<>();
+ insertRows.add(Arrays.asList("?", "?", "?", "?"));
+
when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(insertRows);
+
+ insertOrUpdateExecutor.buildImageSQL(tableMeta);
+ Assertions.assertNotNull(insertOrUpdateExecutor.getSelectSQL());
+ }
+
+ @Test
+ public void testGetParamAppenderList() {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+
+ List<List<Object>> insertRows = new ArrayList<>();
+ insertRows.add(Arrays.asList("?", "?", "?", "?"));
+
when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(insertRows);
+
+ insertOrUpdateExecutor.buildImageSQL(tableMeta);
+
Assertions.assertNotNull(insertOrUpdateExecutor.getParamAppenderList());
+
Assertions.assertTrue(insertOrUpdateExecutor.getParamAppenderList().size() > 0);
+ }
+
+ protected void mockAllIndexes() {
+ Map<String, IndexMeta> allIndex = new LowerCaseLinkHashMap<>();
IndexMeta unique = new IndexMeta();
- unique.setIndextype(IndexType.PRIMARY);
+ unique.setIndextype(IndexType.UNIQUE);
ColumnMeta columnMetaUnique = new ColumnMeta();
columnMetaUnique.setColumnName("user_id");
unique.setValues(Lists.newArrayList(columnMetaUnique));
- allIndex.put("user_id", unique);
+ allIndex.put("user_id_unique", unique);
+
+ IndexMeta primary = new IndexMeta();
+ primary.setIndextype(IndexType.PRIMARY);
+ ColumnMeta columnMeta = new ColumnMeta();
+ columnMeta.setColumnName("id");
+ primary.setValues(Lists.newArrayList(columnMeta));
+ allIndex.put("PRIMARY", primary);
when(tableMeta.getAllIndexes()).thenReturn(allIndex);
}
@@ -296,4 +437,417 @@ public class MySQLInsertOnDuplicateUpdateExecutorTest {
rows.add(Arrays.asList("?", "?", "?", "?"));
when(sqlInsertRecognizer.getInsertRows(pkIndexMap.values())).thenReturn(rows);
}
+
+ protected void mockParametersWithoutPkColumn() {
+ Map<Integer, ArrayList<Object>> parameters = new HashMap<>(4);
+ ArrayList<Object> userId1 = new ArrayList<>();
+ userId1.add("userId1");
+ ArrayList<Object> userName1 = new ArrayList<>();
+ userName1.add("userName1");
+ ArrayList<Object> userStatus1 = new ArrayList<>();
+ userStatus1.add("userStatus1");
+ parameters.put(1, userId1);
+ parameters.put(2, userName1);
+ parameters.put(3, userStatus1);
+
+ ArrayList<Object> userId2 = new ArrayList<>();
+ userId2.add("userId2");
+ ArrayList<Object> userName2 = new ArrayList<>();
+ userName2.add("userName2");
+ ArrayList<Object> userStatus2 = new ArrayList<>();
+ userStatus2.add("userStatus2");
+ parameters.put(4, userId2);
+ parameters.put(5, userName2);
+ parameters.put(6, userStatus2);
+ PreparedStatementProxy psp = (PreparedStatementProxy)
this.statementProxy;
+ when(psp.getParameters()).thenReturn(parameters);
+ }
+
+ @Test
+ public void executeAutoCommitFalseInsertScenarioTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+
when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Collections.singletonList(ID_COLUMN));
+
+ TableRecords emptyBeforeImage = TableRecords.empty(tableMeta);
+ TableRecords afterImage = new TableRecords(tableMeta);
+ doReturn(emptyBeforeImage).when(insertOrUpdateExecutor).beforeImage();
+
+ PreparedStatementProxy psp = (PreparedStatementProxy) statementProxy;
+ when(psp.getUpdateCount()).thenReturn(2);
+
+ StatementCallback callback = mock(StatementCallback.class);
+ when(callback.execute(any(), any())).thenReturn(null);
+ MySQLInsertOnDuplicateUpdateExecutor executor =
+ spy(new MySQLInsertOnDuplicateUpdateExecutor(statementProxy,
callback, sqlInsertRecognizer));
+ doReturn(pkIndexMap).when(executor).getPkIndex();
+ doReturn(tableMeta).when(executor).getTableMeta();
+ doReturn("SELECT * FROM test_table WHERE id =
?").when(executor).buildImageSQL(any(TableMeta.class));
+ doReturn(emptyBeforeImage).when(executor).beforeImage();
+ doReturn(afterImage)
+ .when(executor)
+ .buildTableRecords2(any(TableMeta.class), any(String.class),
any(ArrayList.class), any(List.class));
+
doReturn("test_lock_key").when(executor).buildLockKey(any(TableRecords.class));
+
+ java.lang.reflect.Field selectSQLField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("selectSQL");
+ selectSQLField.setAccessible(true);
+ selectSQLField.set(executor, "SELECT * FROM test_table WHERE id = ?");
+
+ java.lang.reflect.Field paramAppenderListField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("paramAppenderList");
+ paramAppenderListField.setAccessible(true);
+ ArrayList<List<Object>> paramList = new ArrayList<>();
+ paramList.add(Arrays.asList(100));
+ paramAppenderListField.set(executor, paramList);
+
+ Method method =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod("executeAutoCommitFalse",
Object[].class);
+ method.setAccessible(true);
+ Object result = method.invoke(executor, (Object) new Object[] {});
+
+ Assertions.assertNull(result);
+ verify(executor, times(1)).beforeImage();
+ }
+
+ @Test
+ public void executeAutoCommitFalseUpdateScenarioTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+
when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Collections.singletonList(ID_COLUMN));
+
+ TableRecords beforeImage = new TableRecords(tableMeta);
+ TableRecords afterImage = new TableRecords(tableMeta);
+ doReturn(beforeImage).when(insertOrUpdateExecutor).beforeImage();
+
+ PreparedStatementProxy psp = (PreparedStatementProxy) statementProxy;
+ when(psp.getUpdateCount()).thenReturn(1);
+
+ StatementCallback callback = mock(StatementCallback.class);
+ when(callback.execute(any(), any())).thenReturn(null);
+ MySQLInsertOnDuplicateUpdateExecutor executor =
+ spy(new MySQLInsertOnDuplicateUpdateExecutor(statementProxy,
callback, sqlInsertRecognizer));
+ doReturn(pkIndexMap).when(executor).getPkIndex();
+ doReturn(tableMeta).when(executor).getTableMeta();
+ doReturn("SELECT * FROM test_table WHERE id =
?").when(executor).buildImageSQL(any(TableMeta.class));
+ doReturn(beforeImage).when(executor).beforeImage();
+ doReturn(afterImage)
+ .when(executor)
+ .buildTableRecords2(any(TableMeta.class), any(String.class),
any(ArrayList.class), any(List.class));
+
doReturn("test_lock_key").when(executor).buildLockKey(any(TableRecords.class));
+
+ java.lang.reflect.Field selectSQLField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("selectSQL");
+ selectSQLField.setAccessible(true);
+ selectSQLField.set(executor, "SELECT * FROM test_table WHERE id = ?");
+
+ java.lang.reflect.Field paramAppenderListField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("paramAppenderList");
+ paramAppenderListField.setAccessible(true);
+ ArrayList<List<Object>> paramList = new ArrayList<>();
+ paramList.add(Arrays.asList(100));
+ paramAppenderListField.set(executor, paramList);
+
+ Method method =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod("executeAutoCommitFalse",
Object[].class);
+ method.setAccessible(true);
+ Object result = method.invoke(executor, (Object) new Object[] {});
+
+ Assertions.assertNull(result);
+ verify(executor, times(1)).beforeImage();
+ }
+
+ @Test
+ public void executeAutoCommitFalseZeroUpdateCountTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+
when(tableMeta.getPrimaryKeyOnlyName()).thenReturn(Collections.singletonList(ID_COLUMN));
+
+ TableRecords emptyBeforeImage = TableRecords.empty(tableMeta);
+ doReturn(emptyBeforeImage).when(insertOrUpdateExecutor).beforeImage();
+
+ PreparedStatementProxy psp = (PreparedStatementProxy) statementProxy;
+ when(psp.getUpdateCount()).thenReturn(0);
+
+ StatementCallback callback = mock(StatementCallback.class);
+ when(callback.execute(any(), any())).thenReturn(null);
+ MySQLInsertOnDuplicateUpdateExecutor executor =
+ spy(new MySQLInsertOnDuplicateUpdateExecutor(statementProxy,
callback, sqlInsertRecognizer));
+ doReturn(pkIndexMap).when(executor).getPkIndex();
+ doReturn(tableMeta).when(executor).getTableMeta();
+ doReturn("SELECT * FROM test_table WHERE id =
?").when(executor).buildImageSQL(any(TableMeta.class));
+ doReturn(emptyBeforeImage).when(executor).beforeImage();
+
+ Method method =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod("executeAutoCommitFalse",
Object[].class);
+ method.setAccessible(true);
+ Object result = method.invoke(executor, (Object) new Object[] {});
+
+ Assertions.assertNull(result);
+ verify(executor, times(1)).beforeImage();
+ }
+
+ @Test
+ public void executeAutoCommitFalseMultiPkNonMySQLTest() throws Exception {
+ ConnectionProxy oracleConnectionProxy = mock(ConnectionProxy.class);
+
when(oracleConnectionProxy.getDbType()).thenReturn(JdbcConstants.ORACLE);
+
+ StatementProxy oracleStatementProxy =
mock(PreparedStatementProxy.class);
+
when(oracleStatementProxy.getConnectionProxy()).thenReturn(oracleConnectionProxy);
+
+ TableMeta multiPkTableMeta = mock(TableMeta.class);
+
when(multiPkTableMeta.getPrimaryKeyOnlyName()).thenReturn(Arrays.asList("id",
"user_id"));
+
+ StatementCallback callback = mock(StatementCallback.class);
+ MySQLInsertOnDuplicateUpdateExecutor executor =
+ spy(new
MySQLInsertOnDuplicateUpdateExecutor(oracleStatementProxy, callback,
sqlInsertRecognizer));
+ doReturn(multiPkTableMeta).when(executor).getTableMeta();
+ doReturn(JdbcConstants.ORACLE).when(executor).getDbType();
+
+ Method method =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod("executeAutoCommitFalse",
Object[].class);
+ method.setAccessible(true);
+
+
Assertions.assertThrows(java.lang.reflect.InvocationTargetException.class, ()
-> {
+ method.invoke(executor, (Object) new Object[] {});
+ });
+ }
+
+ @Test
+ public void buildUndoItemInsertTypeTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ when(sqlInsertRecognizer.getTableName()).thenReturn("test_table");
+
+ TableRecords emptyBeforeImage = TableRecords.empty(tableMeta);
+ TableRecords afterImage = new TableRecords(tableMeta);
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "buildUndoItem", SQLType.class, TableRecords.class,
TableRecords.class);
+ method.setAccessible(true);
+ SQLUndoLog result =
+ (SQLUndoLog) method.invoke(insertOrUpdateExecutor,
SQLType.INSERT, emptyBeforeImage, afterImage);
+
+ Assertions.assertNotNull(result);
+ Assertions.assertEquals(SQLType.INSERT, result.getSqlType());
+ Assertions.assertEquals("test_table", result.getTableName());
+ Assertions.assertEquals(emptyBeforeImage, result.getBeforeImage());
+ Assertions.assertEquals(afterImage, result.getAfterImage());
+ }
+
+ @Test
+ public void buildUndoItemUpdateTypeTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ when(sqlInsertRecognizer.getTableName()).thenReturn("test_table");
+
+ TableRecords beforeImage = new TableRecords(tableMeta);
+ TableRecords afterImage = new TableRecords(tableMeta);
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "buildUndoItem", SQLType.class, TableRecords.class,
TableRecords.class);
+ method.setAccessible(true);
+ SQLUndoLog result = (SQLUndoLog) method.invoke(insertOrUpdateExecutor,
SQLType.UPDATE, beforeImage, afterImage);
+
+ Assertions.assertNotNull(result);
+ Assertions.assertEquals(SQLType.UPDATE, result.getSqlType());
+ Assertions.assertEquals("test_table", result.getTableName());
+ Assertions.assertEquals(beforeImage, result.getBeforeImage());
+ Assertions.assertEquals(afterImage, result.getAfterImage());
+ }
+
+ @Test
+ public void prepareUndoLogAllEmptyImagesTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+
+ TableRecords emptyBeforeImage = TableRecords.empty(tableMeta);
+ TableRecords emptyAfterImage = TableRecords.empty(tableMeta);
+
+ ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "prepareUndoLogAll", TableRecords.class, TableRecords.class);
+ method.setAccessible(true);
+ method.invoke(insertOrUpdateExecutor, emptyBeforeImage,
emptyAfterImage);
+
+ verify(connectionProxy, times(0)).appendLockKey(any());
+ }
+
+ @Test
+ public void buildUndoItemAllPureInsertTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ when(tableMeta.getTableName()).thenReturn("test_table");
+
+ TableRecords emptyBeforeImage = TableRecords.empty(tableMeta);
+ TableRecords afterImage = new TableRecords(tableMeta);
+ Row afterRow = new Row();
+ Field pkField = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField.setKeyType(KeyType.PRIMARY_KEY);
+ afterRow.add(pkField);
+ afterImage.add(afterRow);
+
+ ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
+
+ java.lang.reflect.Field isUpdateFlagField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("isUpdateFlag");
+ isUpdateFlagField.setAccessible(true);
+ isUpdateFlagField.setBoolean(insertOrUpdateExecutor, false);
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "buildUndoItemAll", ConnectionProxy.class, TableRecords.class,
TableRecords.class);
+ method.setAccessible(true);
+ method.invoke(insertOrUpdateExecutor, connectionProxy,
emptyBeforeImage, afterImage);
+
+ verify(connectionProxy, times(1)).appendUndoLog(any(SQLUndoLog.class));
+ }
+
+ @Test
+ public void buildUndoItemAllPureUpdateTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ when(tableMeta.getTableName()).thenReturn("test_table");
+
+ TableRecords beforeImage = new TableRecords(tableMeta);
+ Row beforeRow = new Row();
+ Field pkField1 = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField1.setKeyType(KeyType.PRIMARY_KEY);
+ beforeRow.add(pkField1);
+ beforeImage.add(beforeRow);
+
+ TableRecords afterImage = new TableRecords(tableMeta);
+ Row afterRow = new Row();
+ Field pkField2 = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField2.setKeyType(KeyType.PRIMARY_KEY);
+ afterRow.add(pkField2);
+ afterImage.add(afterRow);
+
+ ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
+
+ java.lang.reflect.Field isUpdateFlagField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("isUpdateFlag");
+ isUpdateFlagField.setAccessible(true);
+ isUpdateFlagField.setBoolean(insertOrUpdateExecutor, true);
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "buildUndoItemAll", ConnectionProxy.class, TableRecords.class,
TableRecords.class);
+ method.setAccessible(true);
+ method.invoke(insertOrUpdateExecutor, connectionProxy, beforeImage,
afterImage);
+
+ verify(connectionProxy, times(1)).appendUndoLog(any(SQLUndoLog.class));
+ }
+
+ @Test
+ public void buildUndoItemAllMixedTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ when(tableMeta.getTableName()).thenReturn("test_table");
+
+ TableRecords beforeImage = new TableRecords(tableMeta);
+ Row beforeRow = new Row();
+ Field pkField1 = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField1.setKeyType(KeyType.PRIMARY_KEY);
+ beforeRow.add(pkField1);
+ beforeImage.add(beforeRow);
+
+ TableRecords afterImage = new TableRecords(tableMeta);
+ Row afterRow1 = new Row();
+ Field pkField2 = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField2.setKeyType(KeyType.PRIMARY_KEY);
+ afterRow1.add(pkField2);
+ afterImage.add(afterRow1);
+
+ Row afterRow2 = new Row();
+ Field pkField3 = new Field("id", java.sql.Types.INTEGER, 101);
+ pkField3.setKeyType(KeyType.PRIMARY_KEY);
+ afterRow2.add(pkField3);
+ afterImage.add(afterRow2);
+
+ ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
+
+ java.lang.reflect.Field isUpdateFlagField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("isUpdateFlag");
+ isUpdateFlagField.setAccessible(true);
+ isUpdateFlagField.setBoolean(insertOrUpdateExecutor, true);
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "buildUndoItemAll", ConnectionProxy.class, TableRecords.class,
TableRecords.class);
+ method.setAccessible(true);
+ method.invoke(insertOrUpdateExecutor, connectionProxy, beforeImage,
afterImage);
+
+ verify(connectionProxy, times(2)).appendUndoLog(any(SQLUndoLog.class));
+ }
+
+ @Test
+ public void buildUndoItemAllSizeMismatchTest() throws Exception {
+ mockParameters();
+ mockInsertColumns();
+ mockAllIndexes();
+ doReturn(pkIndexMap).when(insertOrUpdateExecutor).getPkIndex();
+ doReturn(tableMeta).when(insertOrUpdateExecutor).getTableMeta();
+ when(tableMeta.getTableName()).thenReturn("test_table");
+
+ TableRecords beforeImage = new TableRecords(tableMeta);
+ Row beforeRow1 = new Row();
+ Field pkField1 = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField1.setKeyType(KeyType.PRIMARY_KEY);
+ beforeRow1.add(pkField1);
+ beforeImage.add(beforeRow1);
+
+ Row beforeRow2 = new Row();
+ Field pkField2 = new Field("id", java.sql.Types.INTEGER, 101);
+ pkField2.setKeyType(KeyType.PRIMARY_KEY);
+ beforeRow2.add(pkField2);
+ beforeImage.add(beforeRow2);
+
+ TableRecords afterImage = new TableRecords(tableMeta);
+ Row afterRow1 = new Row();
+ Field pkField3 = new Field("id", java.sql.Types.INTEGER, 100);
+ pkField3.setKeyType(KeyType.PRIMARY_KEY);
+ afterRow1.add(pkField3);
+ afterImage.add(afterRow1);
+
+ ConnectionProxy connectionProxy = statementProxy.getConnectionProxy();
+
+ java.lang.reflect.Field isUpdateFlagField =
+
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredField("isUpdateFlag");
+ isUpdateFlagField.setAccessible(true);
+ isUpdateFlagField.setBoolean(insertOrUpdateExecutor, true);
+
+ Method method =
MySQLInsertOnDuplicateUpdateExecutor.class.getDeclaredMethod(
+ "buildUndoItemAll", ConnectionProxy.class, TableRecords.class,
TableRecords.class);
+ method.setAccessible(true);
+
+
Assertions.assertThrows(java.lang.reflect.InvocationTargetException.class, ()
-> {
+ method.invoke(insertOrUpdateExecutor, connectionProxy,
beforeImage, afterImage);
+ });
+ }
}
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/PolarDBXInsertOnDuplicateUpdateExecutorTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/PolarDBXInsertOnDuplicateUpdateExecutorTest.java
index e524ae1d21..eb4af03aaf 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/PolarDBXInsertOnDuplicateUpdateExecutorTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/exec/PolarDBXInsertOnDuplicateUpdateExecutorTest.java
@@ -47,8 +47,6 @@ import static org.mockito.Mockito.when;
*/
public class PolarDBXInsertOnDuplicateUpdateExecutorTest extends
MySQLInsertOnDuplicateUpdateExecutorTest {
- protected PolarDBXInsertOnDuplicateUpdateExecutor insertOrUpdateExecutor;
-
@BeforeEach
@Override
public void init() {
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/KingbaseTableMetaCacheTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/KingbaseTableMetaCacheTest.java
new file mode 100644
index 0000000000..98850cd961
--- /dev/null
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/KingbaseTableMetaCacheTest.java
@@ -0,0 +1,335 @@
+/*
+ * 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.seata.rm.datasource.sql.struct.cache;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import org.apache.seata.common.exception.ShouldNeverHappenException;
+import org.apache.seata.rm.datasource.DataSourceProxy;
+import org.apache.seata.rm.datasource.DataSourceProxyTest;
+import org.apache.seata.rm.datasource.mock.MockDriver;
+import org.apache.seata.rm.datasource.sql.struct.TableMetaCacheFactory;
+import org.apache.seata.sqlparser.struct.IndexMeta;
+import org.apache.seata.sqlparser.struct.IndexType;
+import org.apache.seata.sqlparser.struct.TableMeta;
+import org.apache.seata.sqlparser.struct.TableMetaCache;
+import org.apache.seata.sqlparser.util.JdbcConstants;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.sql.SQLException;
+import java.sql.Types;
+
+public class KingbaseTableMetaCacheTest {
+
+ private static final Object[][] COLUMN_METAS = new Object[][] {
+ new Object[] {"", "", "kt1", "id", Types.INTEGER, "INTEGER", 64, 0,
10, 1, "", "", 0, 0, 64, 1, "NO", "YES"},
+ new Object[] {"", "", "kt1", "name1", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 2, "YES", "NO"},
+ new Object[] {"", "", "kt1", "name2", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 3, "YES", "NO"},
+ new Object[] {"", "", "kt1", "name3", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 4, "YES", "NO"}
+ };
+
+ private static final Object[][] INDEX_METAS = new Object[][] {
+ new Object[] {"idx_id", "id", false, "", 3, 0, "A", 34},
+ new Object[] {"idx_name1", "name1", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_name2", "name2", true, "", 3, 2, "A", 34},
+ };
+
+ private static final Object[][] PK_METAS = new Object[][] {new Object[]
{"id"}};
+
+ private static final Object[][] TABLE_METAS = new Object[][] {new Object[]
{"", "kb", "kt1"}};
+
+ @Test
+ public void testGetTableMetaBasic() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ Assertions.assertEquals(3, tableMeta.getAllIndexes().size());
+ }
+
+ @Test
+ public void testGetTableMetaWithSchemaPrefix() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals("KT1", tableMeta.getTableName());
+ Assertions.assertEquals("kb.kt1", tableMeta.getOriginalTableName());
+ }
+
+ @Test
+ public void testGetTableMetaWithQuotedIdentifiers() throws SQLException {
+ Object[][] quotedTableMetas = new Object[][] {new Object[] {"", "KB",
"MixedCase"}};
+ Object[][] quotedColumnMetas = new Object[][] {
+ new Object[] {
+ "", "", "MixedCase", "Id", Types.INTEGER, "INTEGER", 64, 0,
10, 1, "", "", 0, 0, 64, 1, "NO", "YES"
+ },
+ new Object[] {
+ "", "", "MixedCase", "Name", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 2, "YES", "NO"
+ }
+ };
+ Object[][] quotedIndexMetas = new Object[][] {new Object[] {"idx_id",
"Id", false, "", 3, 0, "A", 34}};
+ Object[][] quotedPKMetas = new Object[][] {new Object[] {"Id"}};
+
+ MockDriver mockDriver = new MockDriver(quotedColumnMetas,
quotedIndexMetas, quotedPKMetas, quotedTableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(),
"KB.\"MixedCase\"", proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals("MixedCase", tableMeta.getTableName());
+ }
+
+ @Test
+ public void testGetTableMetaThrowsExceptionWhenNoIndex() throws
SQLException {
+ Object[][] emptyIndexMetas = new Object[][] {};
+ Object[][] emptyTableMetas = new Object[][] {new Object[] {"", "kb",
"kt1"}};
+
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, emptyIndexMetas,
PK_METAS, emptyTableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ Assertions.assertThrows(ShouldNeverHappenException.class, () -> {
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kt1",
proxy.getResourceId());
+ });
+ }
+
+ @Test
+ public void testGetTableMetaWithCompositeIndex() throws SQLException {
+ Object[][] compositeIndexMetas = new Object[][] {
+ new Object[] {"idx_pk", "id", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_composite", "name1", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_composite", "name2", false, "", 3, 2, "A", 34}
+ };
+
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS,
compositeIndexMetas, PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertTrue(tableMeta.getAllIndexes().size() >= 1);
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ }
+
+ @Test
+ public void testGetTableMetaWithPrimaryKeyIndex() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ IndexMeta pkIndex = tableMeta.getAllIndexes().get("idx_id");
+ Assertions.assertNotNull(pkIndex);
+ Assertions.assertEquals(IndexType.PRIMARY, pkIndex.getIndextype());
+ }
+
+ @Test
+ public void testGetTableMetaWithUniqueIndex() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ IndexMeta uniqueIndex = tableMeta.getAllIndexes().get("idx_name1");
+ Assertions.assertNotNull(uniqueIndex);
+ Assertions.assertEquals(IndexType.UNIQUE, uniqueIndex.getIndextype());
+ }
+
+ @Test
+ public void testGetTableMetaWithNormalIndex() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ IndexMeta normalIndex = tableMeta.getAllIndexes().get("idx_name2");
+ Assertions.assertNotNull(normalIndex);
+ Assertions.assertEquals(IndexType.NORMAL, normalIndex.getIndextype());
+ }
+
+ @Test
+ public void testGetTableMetaWithNullIndexName() throws SQLException {
+ Object[][] nullIndexMetas = new Object[][] {
+ new Object[] {"idx_id", "id", false, "", 3, 0, "A", 34},
+ new Object[] {null, "name1", false, "", 3, 1, "A", 34}
+ };
+
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, nullIndexMetas,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertTrue(tableMeta.getAllIndexes().containsKey("idx_id"));
+ Assertions.assertFalse(tableMeta.getAllIndexes().containsKey(null));
+ }
+
+ @Test
+ public void testGetTableMetaCaching() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta1 =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+ TableMeta tableMeta2 =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "KB.KT1",
proxy.getResourceId());
+
+ Assertions.assertSame(tableMeta1, tableMeta2, "Cache should return
same instance");
+ }
+
+ @Test
+ public void testGetTableMetaWithoutSchemaPrefix() throws SQLException {
+ Object[][] singleTableMetas = new Object[][] {new Object[] {"",
"public", "kt1"}};
+
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, singleTableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals("KT1", tableMeta.getTableName());
+ }
+
+ @Test
+ public void testGetTableMetaWithLowerCaseTable() throws SQLException {
+ Object[][] lowerCaseTableMetas = new Object[][] {new Object[] {"",
"kb", "lowertable"}};
+ Object[][] lowerCaseColumnMetas = new Object[][] {
+ new Object[] {
+ "", "", "lowertable", "id", Types.INTEGER, "INTEGER", 64, 0,
10, 1, "", "", 0, 0, 64, 1, "NO", "YES"
+ }
+ };
+ Object[][] lowerCaseIndexMetas = new Object[][] {new Object[]
{"idx_id", "id", false, "", 3, 0, "A", 34}};
+ Object[][] lowerCasePKMetas = new Object[][] {new Object[] {"id"}};
+
+ MockDriver mockDriver =
+ new MockDriver(lowerCaseColumnMetas, lowerCaseIndexMetas,
lowerCasePKMetas, lowerCaseTableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(),
"lowertable", proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ }
+
+ @Test
+ public void testGetTableMetaWithMultiplePrimaryKeys() throws SQLException {
+ Object[][] multiPKMetas = new Object[][] {new Object[] {"id"}, new
Object[] {"name1"}};
+ Object[][] multiPKIndexMetas = new Object[][] {
+ new Object[] {"idx_composite_pk", "id", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_composite_pk", "name1", false, "", 3, 2, "A",
34}
+ };
+
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS,
multiPKIndexMetas, multiPKMetas, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "kb.kt1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertTrue(tableMeta.getPrimaryKeyMap().size() >= 1);
+ Assertions.assertTrue(tableMeta.getAllIndexes().size() >= 1);
+ }
+
+ @Test
+ public void testGetTableMetaOriginalTableNamePreserved() throws
SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:kingbase");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.KINGBASE);
+
+ String originalName = "kb.kt1";
+ TableMeta tableMeta =
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(),
originalName, proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals(originalName,
tableMeta.getOriginalTableName());
+ }
+}
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
index 1d04fa2e37..4c213ea4a0 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
@@ -17,10 +17,14 @@
package org.apache.seata.rm.datasource.sql.struct.cache;
import com.alibaba.druid.pool.DruidDataSource;
+import org.apache.seata.common.exception.ShouldNeverHappenException;
import org.apache.seata.rm.datasource.DataSourceProxy;
import org.apache.seata.rm.datasource.DataSourceProxyTest;
import org.apache.seata.rm.datasource.mock.MockDriver;
import org.apache.seata.rm.datasource.sql.struct.TableMetaCacheFactory;
+import org.apache.seata.sqlparser.struct.ColumnMeta;
+import org.apache.seata.sqlparser.struct.IndexMeta;
+import org.apache.seata.sqlparser.struct.IndexType;
import org.apache.seata.sqlparser.struct.TableMeta;
import org.apache.seata.sqlparser.struct.TableMetaCache;
import org.apache.seata.sqlparser.util.JdbcConstants;
@@ -30,6 +34,8 @@ import org.junit.jupiter.api.Test;
import java.sql.SQLException;
import java.sql.Types;
+import static org.junit.jupiter.api.Assertions.*;
+
/**
*/
public class OracleTableMetaCacheTest {
@@ -72,4 +78,267 @@ public class OracleTableMetaCacheTest {
Assertions.assertNotNull(tableMeta);
}
+
+ @Test
+ public void testGetTableMetaCaching() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta1 =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+ TableMeta tableMeta2 =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.OT1",
proxy.getResourceId());
+
+ Assertions.assertSame(tableMeta1, tableMeta2, "Cache should return
same instance");
+ }
+
+ @Test
+ public void testGetTableMetaWithNoIndexThrowsException() throws
SQLException {
+ Object[][] emptyIndexMetas = new Object[][] {};
+ Object[][] tableMetasForTest = new Object[][] {new Object[] {"", "t",
"ot2"}};
+
+ MockDriver mockDriver = new MockDriver(columnMetas, emptyIndexMetas,
pkMetas, tableMetasForTest);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ Assertions.assertThrows(ShouldNeverHappenException.class, () -> {
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot2",
proxy.getResourceId());
+ });
+ }
+
+ @Test
+ public void testGetTableMetaWithLowerCaseColumns() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ ColumnMeta column = tableMeta.getColumnMeta("name1");
+ Assertions.assertNotNull(column);
+ Assertions.assertEquals("name1", column.getColumnName());
+ }
+
+ @Test
+ public void testGetTableMetaWithDuplicateColumnNames() throws SQLException
{
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ }
+
+ @Test
+ public void testGetTableMetaWithCompositeIndex() throws SQLException {
+ Object[][] compositeIndexMetas = new Object[][] {
+ new Object[] {"idx_pk", "id", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_composite", "name1", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_composite", "name2", false, "", 3, 2, "A", 34}
+ };
+
+ MockDriver mockDriver = new MockDriver(columnMetas,
compositeIndexMetas, pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertTrue(tableMeta.getAllIndexes().size() >= 1);
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ }
+
+ @Test
+ public void testGetTableMetaWithPrimaryKeyIndex() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ IndexMeta pkIndex = tableMeta.getAllIndexes().get("id");
+ Assertions.assertNotNull(pkIndex);
+ Assertions.assertEquals(IndexType.PRIMARY, pkIndex.getIndextype());
+ }
+
+ @Test
+ public void testGetTableMetaWithUniqueIndex() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ IndexMeta uniqueIndex = tableMeta.getAllIndexes().get("name1");
+ Assertions.assertNotNull(uniqueIndex);
+ Assertions.assertEquals(IndexType.UNIQUE, uniqueIndex.getIndextype());
+ }
+
+ @Test
+ public void testGetTableMetaWithNormalIndex() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ IndexMeta normalIndex = tableMeta.getAllIndexes().get("name2");
+ Assertions.assertNotNull(normalIndex);
+ Assertions.assertEquals(IndexType.NORMAL, normalIndex.getIndextype());
+ }
+
+ @Test
+ public void testGetTableMetaWithNullIndexName() throws SQLException {
+ Object[][] nullIndexMetas = new Object[][] {
+ new Object[] {"idx_id", "id", false, "", 3, 0, "A", 34},
+ new Object[] {null, "name1", false, "", 3, 1, "A", 34}
+ };
+
+ MockDriver mockDriver = new MockDriver(columnMetas, nullIndexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertTrue(tableMeta.getAllIndexes().size() >= 1);
+ }
+
+ @Test
+ public void testGetTableMetaWithPrimaryKeyConstraintDifferentName() throws
SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ ColumnMeta pkColumn = tableMeta.getPrimaryKeyMap().get("id");
+ Assertions.assertNotNull(pkColumn);
+ Assertions.assertEquals("id", pkColumn.getColumnName());
+ Assertions.assertTrue(tableMeta.getAllIndexes().size() >= 1);
+ }
+
+ @Test
+ public void testGetTableMetaOriginalTableNamePreserved() throws
SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ String originalName = "t.ot1";
+ TableMeta tableMeta =
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(),
originalName, proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals(originalName,
tableMeta.getOriginalTableName());
+ }
+
+ @Test
+ public void testGetTableMetaWithMultiplePrimaryKeys() throws SQLException {
+ Object[][] multiPKMetas = new Object[][] {new Object[] {"id"}, new
Object[] {"name1"}};
+ Object[][] multiPKIndexMetas = new Object[][] {
+ new Object[] {"idx_composite_pk", "id", false, "", 3, 1, "A", 34},
+ new Object[] {"idx_composite_pk", "name1", false, "", 3, 2, "A",
34}
+ };
+
+ MockDriver mockDriver = new MockDriver(columnMetas, multiPKIndexMetas,
multiPKMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertTrue(tableMeta.getPrimaryKeyMap().size() >= 1);
+ Assertions.assertTrue(tableMeta.getAllIndexes().size() >= 1);
+ }
+
+ @Test
+ public void testGetTableMetaWithQuotedTableName() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(),
"t.\"ot1\"", proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ }
+
+ @Test
+ public void testGetTableMetaAllColumnsPresent() throws SQLException {
+ MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+
+ TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+
+ Assertions.assertNotNull(tableMeta);
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ Assertions.assertNotNull(tableMeta.getColumnMeta("id"));
+ Assertions.assertNotNull(tableMeta.getColumnMeta("name1"));
+ Assertions.assertNotNull(tableMeta.getColumnMeta("name2"));
+ Assertions.assertNotNull(tableMeta.getColumnMeta("name3"));
+ }
}
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OscarTableMetaCacheTest.java
similarity index 54%
copy from
rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
copy to
rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OscarTableMetaCacheTest.java
index 1d04fa2e37..d34f6efb8b 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OracleTableMetaCacheTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/sql/struct/cache/OscarTableMetaCacheTest.java
@@ -30,46 +30,73 @@ import org.junit.jupiter.api.Test;
import java.sql.SQLException;
import java.sql.Types;
-/**
- */
-public class OracleTableMetaCacheTest {
+public class OscarTableMetaCacheTest {
- private static Object[][] columnMetas = new Object[][] {
+ private static final Object[][] COLUMN_METAS = new Object[][] {
new Object[] {"", "", "ot1", "id", Types.INTEGER, "INTEGER", 64, 0,
10, 1, "", "", 0, 0, 64, 1, "NO", "YES"},
new Object[] {"", "", "ot1", "name1", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 2, "YES", "NO"},
new Object[] {"", "", "ot1", "name2", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 3, "YES", "NO"},
new Object[] {"", "", "ot1", "name3", Types.VARCHAR, "VARCHAR", 64, 0,
10, 0, "", "", 0, 0, 64, 4, "YES", "NO"}
};
- private static Object[][] indexMetas = new Object[][] {
+ private static final Object[][] INDEX_METAS = new Object[][] {
new Object[] {"id", "id", false, "", 3, 0, "A", 34},
new Object[] {"name1", "name1", false, "", 3, 1, "A", 34},
new Object[] {"name2", "name2", true, "", 3, 2, "A", 34},
};
- private static Object[][] pkMetas = new Object[][] {new Object[] {"id"}};
+ private static final Object[][] PK_METAS = new Object[][] {new Object[]
{"id"}};
- private static Object[][] tableMetas = new Object[][] {new Object[] {"",
"t", "ot1"}};
+ private static final Object[][] TABLE_METAS = new Object[][] {new Object[]
{"", "t", "ot1"}};
@Test
- public void getTableMetaTest() throws SQLException {
- MockDriver mockDriver = new MockDriver(columnMetas, indexMetas,
pkMetas, tableMetas);
+ public void testGetTableMetaWithSchemaAndTable() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:mock:xxx");
dataSource.setDriver(mockDriver);
DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
- TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.ORACLE);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.OSCAR);
TableMeta tableMeta =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
Assertions.assertNotNull(tableMeta);
- Assertions.assertEquals("OT1", tableMeta.getTableName());
- Assertions.assertEquals("t.ot1", tableMeta.getOriginalTableName());
+ Assertions.assertEquals("t.ot1", tableMeta.getTableName());
+ Assertions.assertEquals(4, tableMeta.getAllColumns().size());
+ }
+
+ @Test
+ public void testGetTableMetaWithQuotedIdentifiers() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.OSCAR);
- tableMeta = tableMetaCache.getTableMeta(proxy.getPlainConnection(),
"t.\"ot1\"", proxy.getResourceId());
+ TableMeta tableMeta =
+ tableMetaCache.getTableMeta(proxy.getPlainConnection(),
"t.\"ot1\"", proxy.getResourceId());
Assertions.assertNotNull(tableMeta);
}
+
+ @Test
+ public void testGetTableMetaCaching() throws SQLException {
+ MockDriver mockDriver = new MockDriver(COLUMN_METAS, INDEX_METAS,
PK_METAS, TABLE_METAS);
+ DruidDataSource dataSource = new DruidDataSource();
+ dataSource.setUrl("jdbc:mock:xxx");
+ dataSource.setDriver(mockDriver);
+
+ DataSourceProxy proxy =
DataSourceProxyTest.getDataSourceProxy(dataSource);
+ TableMetaCache tableMetaCache =
TableMetaCacheFactory.getTableMetaCache(JdbcConstants.OSCAR);
+
+ TableMeta tableMeta1 =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.ot1",
proxy.getResourceId());
+ TableMeta tableMeta2 =
tableMetaCache.getTableMeta(proxy.getPlainConnection(), "t.OT1",
proxy.getResourceId());
+
+ Assertions.assertSame(tableMeta1, tableMeta2, "Cache should return
same instance");
+ }
}
diff --git
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/util/JdbcUtilsTest.java
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/util/JdbcUtilsTest.java
index 0b1ae4134e..64a2003948 100644
---
a/rm-datasource/src/test/java/org/apache/seata/rm/datasource/util/JdbcUtilsTest.java
+++
b/rm-datasource/src/test/java/org/apache/seata/rm/datasource/util/JdbcUtilsTest.java
@@ -16,14 +16,280 @@
*/
package org.apache.seata.rm.datasource.util;
+import org.apache.seata.rm.BaseDataSourceResource;
+import org.apache.seata.rm.DefaultResourceManager;
import org.apache.seata.sqlparser.util.DbTypeParser;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import javax.sql.DataSource;
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.Driver;
+import java.sql.SQLException;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
public class JdbcUtilsTest {
+
+ private static final String MYSQL_URL = "jdbc:mysql://localhost:3306/test";
+ private static final String MYSQL_URL_WITH_PARAMS =
+ "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC";
+ private static final String ORACLE_URL =
"jdbc:oracle:thin:@localhost:1521:orcl";
+ private static final String POSTGRESQL_URL =
"jdbc:postgresql://localhost:5432/test";
+ private static final String H2_URL = "jdbc:h2:mem:test";
+
+ private MockedStatic<DefaultResourceManager> mockedResourceManager;
+ private DefaultResourceManager resourceManager;
+
+ @BeforeEach
+ public void setUp() {
+ resourceManager = mock(DefaultResourceManager.class);
+ mockedResourceManager =
Mockito.mockStatic(DefaultResourceManager.class);
+
mockedResourceManager.when(DefaultResourceManager::get).thenReturn(resourceManager);
+ }
+
+ @AfterEach
+ public void tearDown() {
+ if (mockedResourceManager != null) {
+ mockedResourceManager.close();
+ }
+ }
+
@Test
public void testDbTypeParserLoading() {
DbTypeParser dbTypeParser = JdbcUtils.getDbTypeParser();
Assertions.assertNotNull(dbTypeParser);
}
+
+ @Test
+ public void testDbTypeParserSingletonPattern() {
+ DbTypeParser first = JdbcUtils.getDbTypeParser();
+ DbTypeParser second = JdbcUtils.getDbTypeParser();
+ assertSame(first, second, "DbTypeParser should be singleton");
+ }
+
+ @Test
+ public void testGetDbTypeWithMySQLUrl() {
+ String dbType = JdbcUtils.getDbType(MYSQL_URL);
+ assertEquals("mysql", dbType);
+ }
+
+ @Test
+ public void testGetDbTypeWithOracleUrl() {
+ String dbType = JdbcUtils.getDbType(ORACLE_URL);
+ assertEquals("oracle", dbType);
+ }
+
+ @Test
+ public void testGetDbTypeWithPostgreSQLUrl() {
+ String dbType = JdbcUtils.getDbType(POSTGRESQL_URL);
+ assertEquals("postgresql", dbType);
+ }
+
+ @Test
+ public void testGetDbTypeWithH2Url() {
+ String dbType = JdbcUtils.getDbType(H2_URL);
+ assertEquals("h2", dbType);
+ }
+
+ @Test
+ public void testBuildResourceIdWithQueryString() {
+ String resourceId = JdbcUtils.buildResourceId(MYSQL_URL_WITH_PARAMS);
+ assertEquals(MYSQL_URL, resourceId, "Should remove query string");
+ }
+
+ @Test
+ public void testBuildResourceIdWithoutQueryString() {
+ String resourceId = JdbcUtils.buildResourceId(MYSQL_URL);
+ assertEquals(MYSQL_URL, resourceId, "Should keep URL unchanged");
+ }
+
+ @Test
+ public void testBuildResourceIdWithEmptyQueryString() {
+ String urlWithEmptyQuery = "jdbc:mysql://localhost:3306/test?";
+ String resourceId = JdbcUtils.buildResourceId(urlWithEmptyQuery);
+ assertEquals(MYSQL_URL, resourceId, "Should remove trailing question
mark");
+ }
+
+ @Test
+ public void testBuildResourceIdWithMultipleQuestionMarks() {
+ String urlWithMultiple =
"jdbc:mysql://localhost:3306/test?param1=value1?param2=value2";
+ String resourceId = JdbcUtils.buildResourceId(urlWithMultiple);
+ assertEquals(MYSQL_URL, resourceId, "Should remove from first question
mark");
+ }
+
+ @Test
+ public void testLoadDriverWithValidH2Driver() throws SQLException {
+ Driver driver = JdbcUtils.loadDriver("org.h2.Driver");
+ assertNotNull(driver, "Should load H2 driver successfully");
+ assertTrue(driver instanceof org.h2.Driver);
+ }
+
+ @Test
+ public void testLoadDriverWithInvalidDriverClass() {
+ SQLException exception = assertThrows(SQLException.class, () -> {
+ JdbcUtils.loadDriver("com.invalid.NonExistentDriver");
+ });
+ assertNotNull(exception.getCause());
+ assertTrue(exception.getCause() instanceof ClassNotFoundException);
+ }
+
+ @Test
+ public void testLoadDriverWithNullClassName() {
+ assertThrows(Exception.class, () -> {
+ JdbcUtils.loadDriver(null);
+ });
+ }
+
+ @Test
+ public void testLoadDriverWithEmptyClassName() {
+ assertThrows(Exception.class, () -> {
+ JdbcUtils.loadDriver("");
+ });
+ }
+
+ @Test
+ public void testInitDataSourceResourceSuccess() throws SQLException {
+ DataSource dataSource = mock(DataSource.class);
+ Connection connection = mock(Connection.class);
+ DatabaseMetaData metaData = mock(DatabaseMetaData.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(dataSource.getConnection()).thenReturn(connection);
+ when(connection.getMetaData()).thenReturn(metaData);
+ when(metaData.getURL()).thenReturn(MYSQL_URL_WITH_PARAMS);
+
+ JdbcUtils.initDataSourceResource(resource, dataSource, "test-group");
+
+ verify(resource).setResourceGroupId("test-group");
+ verify(resource).setResourceId(MYSQL_URL);
+ verify(resource).setDbType("mysql");
+ verify(resource).setDriver(any(Driver.class));
+ verify(resourceManager).registerResource(resource);
+ verify(connection).close();
+ }
+
+ @Test
+ public void testInitDataSourceResourceWithSQLException() throws
SQLException {
+ DataSource dataSource = mock(DataSource.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(dataSource.getConnection()).thenThrow(new
SQLException("Connection failed"));
+
+ IllegalStateException exception =
assertThrows(IllegalStateException.class, () -> {
+ JdbcUtils.initDataSourceResource(resource, dataSource,
"test-group");
+ });
+
+ assertTrue(exception.getMessage().contains("can not init
DataSourceResource"));
+ assertNotNull(exception.getCause());
+ assertTrue(exception.getCause() instanceof SQLException);
+ verify(resource).setResourceGroupId("test-group");
+ verify(resourceManager, never()).registerResource(any());
+ }
+
+ @Test
+ public void testInitDataSourceResourceWithNullMetaData() throws
SQLException {
+ DataSource dataSource = mock(DataSource.class);
+ Connection connection = mock(Connection.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(dataSource.getConnection()).thenReturn(connection);
+ when(connection.getMetaData()).thenReturn(null);
+
+ assertThrows(Exception.class, () -> {
+ JdbcUtils.initDataSourceResource(resource, dataSource,
"test-group");
+ });
+
+ verify(connection).close();
+ }
+
+ @Test
+ public void testInitXADataSourceResourceSuccess() throws SQLException {
+ XADataSource xaDataSource = mock(XADataSource.class);
+ XAConnection xaConnection = mock(XAConnection.class);
+ Connection connection = mock(Connection.class);
+ DatabaseMetaData metaData = mock(DatabaseMetaData.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(xaDataSource.getXAConnection()).thenReturn(xaConnection);
+ when(xaConnection.getConnection()).thenReturn(connection);
+ when(connection.getMetaData()).thenReturn(metaData);
+ when(metaData.getURL()).thenReturn(H2_URL);
+
+ JdbcUtils.initXADataSourceResource(resource, xaDataSource, "xa-group");
+
+ verify(resource).setResourceGroupId("xa-group");
+ verify(resource).setResourceId(H2_URL);
+ verify(resource).setDbType("h2");
+ verify(resource).setDriver(any(Driver.class));
+ verify(resourceManager).registerResource(resource);
+ verify(connection).close();
+ verify(xaConnection).close();
+ }
+
+ @Test
+ public void testInitXADataSourceResourceWithSQLException() throws
SQLException {
+ XADataSource xaDataSource = mock(XADataSource.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(xaDataSource.getXAConnection()).thenThrow(new SQLException("XA
connection failed"));
+
+ IllegalStateException exception =
assertThrows(IllegalStateException.class, () -> {
+ JdbcUtils.initXADataSourceResource(resource, xaDataSource,
"xa-group");
+ });
+
+ assertTrue(exception.getMessage().contains("can not get
XAConnection"));
+ assertNotNull(exception.getCause());
+ assertTrue(exception.getCause() instanceof SQLException);
+ verify(resource).setResourceGroupId("xa-group");
+ verify(resourceManager, never()).registerResource(any());
+ }
+
+ @Test
+ public void testInitXADataSourceResourceWithNullXAConnection() throws
SQLException {
+ XADataSource xaDataSource = mock(XADataSource.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(xaDataSource.getXAConnection()).thenReturn(null);
+
+ assertThrows(Exception.class, () -> {
+ JdbcUtils.initXADataSourceResource(resource, xaDataSource,
"xa-group");
+ });
+
+ verify(resource).setResourceGroupId("xa-group");
+ verify(resourceManager, never()).registerResource(any());
+ }
+
+ @Test
+ public void testInitXADataSourceResourceEnsuresConnectionClosed() throws
SQLException {
+ XADataSource xaDataSource = mock(XADataSource.class);
+ XAConnection xaConnection = mock(XAConnection.class);
+ Connection connection = mock(Connection.class);
+ DatabaseMetaData metaData = mock(DatabaseMetaData.class);
+ BaseDataSourceResource resource = mock(BaseDataSourceResource.class);
+
+ when(xaDataSource.getXAConnection()).thenReturn(xaConnection);
+ when(xaConnection.getConnection()).thenReturn(connection);
+ when(connection.getMetaData()).thenReturn(metaData);
+ when(metaData.getURL()).thenReturn(H2_URL);
+ doThrow(new SQLException("Close failed")).when(xaConnection).close();
+
+ try {
+ JdbcUtils.initXADataSourceResource(resource, xaDataSource,
"xa-group");
+ } catch (Exception e) {
+ // Expected
+ }
+
+ verify(connection).close();
+ verify(xaConnection).close();
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]