This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new 37657364b96 Add more test cases on StandardDatabaseProxyConnectorTest
(#38051)
37657364b96 is described below
commit 37657364b9621389154a8a62791bc55e8beb37cd
Author: Liang Zhang <[email protected]>
AuthorDate: Sun Feb 15 23:50:57 2026 +0800
Add more test cases on StandardDatabaseProxyConnectorTest (#38051)
* Add more test cases on StandardDatabaseProxyConnectorTest
* Add more test cases on StandardDatabaseProxyConnectorTest
---
.../StandardDatabaseProxyConnectorTest.java | 664 ++++++++++++++++++++-
1 file changed, 648 insertions(+), 16 deletions(-)
diff --git
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
index 099e6004cc3..178ec4e8a74 100644
---
a/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
+++
b/proxy/backend/core/src/test/java/org/apache/shardingsphere/proxy/backend/connector/StandardDatabaseProxyConnectorTest.java
@@ -18,14 +18,32 @@
package org.apache.shardingsphere.proxy.backend.connector;
import lombok.SneakyThrows;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.DialectDatabaseMetaData;
+import
org.apache.shardingsphere.database.connector.core.metadata.database.metadata.option.transaction.DialectTransactionOption;
import
org.apache.shardingsphere.database.connector.core.spi.DatabaseTypedSPILoader;
import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.database.connector.core.type.DatabaseTypeRegistry;
+import
org.apache.shardingsphere.infra.binder.context.segment.insert.keygen.GeneratedKeyContext;
+import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
+import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.ProjectionsContext;
import
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
+import
org.apache.shardingsphere.infra.binder.context.statement.type.ddl.CursorHeldSQLStatementContext;
+import
org.apache.shardingsphere.infra.binder.context.statement.type.ddl.CursorStatementContext;
+import
org.apache.shardingsphere.infra.binder.context.statement.type.dml.InsertStatementContext;
+import
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
+import org.apache.shardingsphere.infra.connection.kernel.KernelProcessor;
+import
org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.EmptyStorageUnitException;
+import
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.EmptyRuleException;
+import org.apache.shardingsphere.infra.executor.sql.context.ExecutionContext;
+import org.apache.shardingsphere.infra.executor.sql.context.ExecutionUnit;
import
org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
import
org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResultMetaData;
+import
org.apache.shardingsphere.infra.executor.sql.execute.result.update.UpdateResult;
import
org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.JDBCDriverType;
import org.apache.shardingsphere.infra.hint.HintValueContext;
+import org.apache.shardingsphere.infra.merge.MergeEngine;
+import org.apache.shardingsphere.infra.merge.result.MergedResult;
import
org.apache.shardingsphere.infra.merge.result.impl.memory.MemoryMergedResult;
import
org.apache.shardingsphere.infra.merge.result.impl.memory.MemoryQueryResultRow;
import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
@@ -40,19 +58,37 @@ import
org.apache.shardingsphere.infra.metadata.database.schema.util.SystemSchem
import
org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics;
import
org.apache.shardingsphere.infra.metadata.statistics.builder.ShardingSphereStatisticsFactory;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
+import
org.apache.shardingsphere.infra.rule.attribute.datanode.DataNodeRuleAttribute;
import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
+import
org.apache.shardingsphere.infra.session.connection.cursor.CursorConnectionContext;
import org.apache.shardingsphere.infra.session.query.QueryContext;
+import org.apache.shardingsphere.infra.spi.ShardingSphereServiceLoader;
import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
import org.apache.shardingsphere.mode.manager.ContextManager;
import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
+import
org.apache.shardingsphere.mode.metadata.refresher.federation.FederationMetaDataRefreshEngine;
+import
org.apache.shardingsphere.mode.metadata.refresher.pushdown.PushDownMetaDataRefreshEngine;
import org.apache.shardingsphere.parser.config.SQLParserRuleConfiguration;
import org.apache.shardingsphere.parser.rule.SQLParserRule;
import
org.apache.shardingsphere.proxy.backend.connector.jdbc.fixture.QueryHeaderBuilderFixture;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.statement.JDBCBackendStatement;
+import
org.apache.shardingsphere.proxy.backend.connector.jdbc.transaction.ProxyBackendTransactionManager;
import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import org.apache.shardingsphere.proxy.backend.response.header.ResponseHeader;
import
org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeaderBuilder;
import
org.apache.shardingsphere.proxy.backend.response.header.query.QueryHeaderBuilderEngine;
+import
org.apache.shardingsphere.proxy.backend.response.header.query.QueryResponseHeader;
+import
org.apache.shardingsphere.proxy.backend.response.header.update.UpdateResponseHeader;
import org.apache.shardingsphere.sharding.rule.ShardingRule;
import org.apache.shardingsphere.sql.parser.engine.api.CacheOption;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.cursor.CursorNameSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.CloseStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.CursorStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
+import
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import org.apache.shardingsphere.sqlfederation.engine.SQLFederationEngine;
import org.apache.shardingsphere.sqlfederation.rule.SQLFederationRule;
import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
@@ -61,6 +97,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.Mock;
+import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.internal.configuration.plugins.Plugins;
import org.mockito.junit.jupiter.MockitoSettings;
@@ -77,15 +114,23 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyList;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -95,6 +140,8 @@ import static org.mockito.Mockito.when;
@StaticMockSettings({ProxyContext.class, SystemSchemaUtils.class})
class StandardDatabaseProxyConnectorTest {
+ private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ProxyDatabaseConnectionManager databaseConnectionManager;
@@ -131,7 +178,9 @@ class StandardDatabaseProxyConnectorTest {
when(result.getName()).thenReturn("foo_db");
when(result.containsDataSource()).thenReturn(true);
when(result.isComplete()).thenReturn(true);
-
when(result.getProtocolType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
"H2"));
+ when(result.getProtocolType()).thenReturn(databaseType);
+
when(result.getRuleMetaData().getRules()).thenReturn(Collections.singleton(mock(ShardingRule.class)));
+
when(result.getRuleMetaData().getAttributes(DataNodeRuleAttribute.class)).thenReturn(Collections.emptyList());
return result;
}
@@ -139,14 +188,13 @@ class StandardDatabaseProxyConnectorTest {
void assertBinaryProtocolQueryHeader() throws SQLException,
NoSuchFieldException, IllegalAccessException {
SQLStatementContext sqlStatementContext =
mock(SQLStatementContext.class, RETURNS_DEEP_STUBS);
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
-
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
"FIXTURE"));
- DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.PREPARED_STATEMENT,
createQueryContext(sqlStatementContext));
+
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.PREPARED_STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
Field queryHeadersField =
StandardDatabaseProxyConnector.class.getDeclaredField("queryHeaders");
ShardingSphereDatabase database = createDatabaseMetaData();
try (MockedStatic<DatabaseTypedSPILoader> spiLoader =
mockStatic(DatabaseTypedSPILoader.class)) {
- spiLoader.when(() ->
DatabaseTypedSPILoader.getService(QueryHeaderBuilder.class,
TypedSPILoader.getService(DatabaseType.class, "MySQL"))).thenReturn(new
QueryHeaderBuilderFixture());
- Plugins.getMemberAccessor().set(queryHeadersField, engine,
- Collections.singletonList(new
QueryHeaderBuilderEngine(TypedSPILoader.getService(DatabaseType.class,
"MySQL")).build(createQueryResultMetaData(), database, 1)));
+ spiLoader.when(() ->
DatabaseTypedSPILoader.getService(QueryHeaderBuilder.class,
databaseType)).thenReturn(new QueryHeaderBuilderFixture());
+ Plugins.getMemberAccessor().set(queryHeadersField, engine,
Collections.singletonList(new
QueryHeaderBuilderEngine(databaseType).build(createQueryResultMetaData(),
database, 1)));
Field mergedResultField =
StandardDatabaseProxyConnector.class.getDeclaredField("mergedResult");
Plugins.getMemberAccessor().set(mergedResultField, engine, new
MemoryMergedResult<ShardingSphereRule>(null, null, null,
Collections.emptyList()) {
@@ -167,18 +215,501 @@ class StandardDatabaseProxyConnectorTest {
}
}
+ @Test
+ void assertExecuteWithFederationMetaDataRefresh() throws SQLException {
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new SQLStatement(databaseType));
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+
when(proxySQLExecutor.getSqlFederationEngine().isSQLFederationEnabled()).thenReturn(true);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ try (
+ MockedConstruction<FederationMetaDataRefreshEngine>
mockedConstruction = mockConstruction(FederationMetaDataRefreshEngine.class,
+ (mock, context) ->
when(mock.isNeedRefresh()).thenReturn(true))) {
+ assertThat(engine.execute(),
instanceOf(UpdateResponseHeader.class));
+ FederationMetaDataRefreshEngine federationMetaDataRefreshEngine =
mockedConstruction.constructed().iterator().next();
+ verify(federationMetaDataRefreshEngine).refresh(any(),
any(ShardingSphereDatabase.class));
+ }
+ }
+
+ @Test
+ void assertExecuteWithImplicitCommitTransaction() throws SQLException {
+
when(databaseConnectionManager.getConnectionSession().isAutoCommit()).thenReturn(true);
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext().getTransactionContext().getTransactionType()).thenReturn(Optional.of("XA"));
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new InsertStatement(databaseType));
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Arrays.asList(mock(ExecutionUnit.class),
mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Collections.singletonList(new
UpdateResult(1, 0L)));
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class)));
+ MockedConstruction<ProxyBackendTransactionManager>
mockedTransactionManager =
mockConstruction(ProxyBackendTransactionManager.class);
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ assertThat(engine.execute(),
instanceOf(UpdateResponseHeader.class));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ ProxyBackendTransactionManager transactionManager =
mockedTransactionManager.constructed().iterator().next();
+ verify(transactionManager).begin();
+ verify(transactionManager).commit();
+ }
+ }
+
+ @Test
+ void assertExecuteWithImplicitCommitTransactionAndException() throws
SQLException {
+
when(databaseConnectionManager.getConnectionSession().isAutoCommit()).thenReturn(true);
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext().getTransactionContext().getTransactionType()).thenReturn(Optional.of("XA"));
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new InsertStatement(databaseType));
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Arrays.asList(mock(ExecutionUnit.class),
mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(proxySQLExecutor.execute(executionContext)).thenThrow(RuntimeException.class);
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
ignoredDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class)));
+ MockedConstruction<ProxyBackendTransactionManager>
mockedTransactionManager =
mockConstruction(ProxyBackendTransactionManager.class);
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ assertThrows(SQLException.class, engine::execute);
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ ProxyBackendTransactionManager transactionManager =
mockedTransactionManager.constructed().iterator().next();
+ verify(transactionManager).begin();
+ verify(transactionManager).rollback();
+ }
+ }
+
+ @Test
+ void assertExecuteWithUpdateResultAndAccumulate() throws SQLException {
+ InsertStatementContext sqlStatementContext =
mock(InsertStatementContext.class, RETURNS_DEEP_STUBS);
+ InsertStatement insertStatement = new InsertStatement(databaseType);
+ insertStatement.buildAttributes();
+
when(sqlStatementContext.getSqlStatement()).thenReturn(insertStatement);
+
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+
when(sqlStatementContext.getTablesContext().getSchemaNames()).thenReturn(Collections.emptyList());
+
when(sqlStatementContext.getTablesContext().getTableNames()).thenReturn(Collections.singleton("t_order"));
+ GeneratedKeyContext generatedKeyContext = new
GeneratedKeyContext("order_id", true);
+ generatedKeyContext.setSupportAutoIncrement(true);
+ generatedKeyContext.getGeneratedValues().add(2L);
+
when(sqlStatementContext.getGeneratedKeyContext()).thenReturn(Optional.of(generatedKeyContext));
+ DataNodeRuleAttribute dataNodeRuleAttribute =
mock(DataNodeRuleAttribute.class);
+
when(dataNodeRuleAttribute.isNeedAccumulate(any(Collection.class))).thenReturn(true);
+ ShardingSphereDatabase database = mockDatabase();
+
when(database.getRuleMetaData().getAttributes(DataNodeRuleAttribute.class)).thenReturn(Collections.singleton(dataNodeRuleAttribute));
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, database));
+ setField(engine, "proxySQLExecutor", mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS));
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.singletonList(mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(executionContext.getRouteContext().getRouteUnits()).thenReturn(Collections.emptyList());
+ AdvancedProxySQLExecutor advancedProxySQLExecutor =
mock(AdvancedProxySQLExecutor.class);
+ when(advancedProxySQLExecutor.execute(any(ExecutionContext.class),
any(ContextManager.class), any(ShardingSphereDatabase.class),
any(DatabaseProxyConnector.class)))
+ .thenReturn(Arrays.asList(new UpdateResult(1, 4L), new
UpdateResult(2, 5L)));
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class)));
+ MockedConstruction<PushDownMetaDataRefreshEngine>
mockedPushDownMetaDataRefreshEngine =
mockConstruction(PushDownMetaDataRefreshEngine.class,
+ (mock, context) ->
when(mock.isNeedRefresh()).thenReturn(true));
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class))
+
.thenReturn(Collections.singleton(advancedProxySQLExecutor));
+ UpdateResponseHeader actual = (UpdateResponseHeader)
engine.execute();
+ assertThat(actual.getUpdateCount(), is(3L));
+ assertThat(actual.getLastInsertId(), is(2L));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ PushDownMetaDataRefreshEngine pushDownMetaDataRefreshEngine =
mockedPushDownMetaDataRefreshEngine.constructed().iterator().next();
+ verify(pushDownMetaDataRefreshEngine).refresh(any(), eq(database),
any(ConfigurationProperties.class), any(Collection.class));
+ }
+ }
+
+ @Test
+ void assertConstructWithSystemSchema() {
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class,
RETURNS_DEEP_STUBS);
+ when(database.getName()).thenReturn("foo_db");
+ when(SystemSchemaUtils.containsSystemSchema(any(DatabaseType.class),
any(Collection.class), any(ShardingSphereDatabase.class))).thenReturn(true);
+ assertNotNull(createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
database)));
+ }
+
+ @Test
+ void assertConstructWithEmptyStorageUnitException() {
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class,
RETURNS_DEEP_STUBS);
+ when(database.getName()).thenReturn("foo_db");
+ when(database.isComplete()).thenReturn(true);
+ QueryContext queryContext =
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
database);
+ assertNotNull(assertThrows(EmptyStorageUnitException.class, () ->
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext)));
+ }
+
+ @Test
+ void assertConstructWithEmptyRuleException() {
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class,
RETURNS_DEEP_STUBS);
+ when(database.getName()).thenReturn("foo_db");
+ when(database.containsDataSource()).thenReturn(true);
+ QueryContext queryContext =
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
database);
+ assertNotNull(assertThrows(EmptyRuleException.class, () ->
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext)));
+ }
+
+ @Test
+ void assertConstructWithCloseAllCursorStatement() {
+ CloseStatement closeStatement = new CloseStatement(databaseType, null,
true);
+ closeStatement.buildAttributes();
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(closeStatement);
+ ConnectionContext connectionContext = mock(ConnectionContext.class,
RETURNS_DEEP_STUBS);
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext()).thenReturn(connectionContext);
+ createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
+ verify(connectionContext).clearCursorContext();
+ }
+
+ @Test
+ void assertConstructWithNotExistedCursorHeldSQLStatementContext() {
+ CursorNameSegment cursorNameSegment = new CursorNameSegment(0, 0, new
IdentifierValue("foo_cursor"));
+ CloseStatement closeStatement = new CloseStatement(databaseType,
cursorNameSegment, false);
+ closeStatement.buildAttributes();
+ CursorHeldSQLStatementContext sqlStatementContext = new
CursorHeldSQLStatementContext(closeStatement);
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext().getCursorContext()).thenReturn(new
CursorConnectionContext());
+ assertNotNull(assertThrows(IllegalArgumentException.class, () ->
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()))));
+ }
+
+ @Test
+ void assertConstructWithCursorHeldSQLStatementContext() {
+ CursorNameSegment cursorNameSegment = new CursorNameSegment(0, 0, new
IdentifierValue("foo_cursor"));
+ CloseStatement closeStatement = new CloseStatement(databaseType,
cursorNameSegment, false);
+ closeStatement.buildAttributes();
+ CursorHeldSQLStatementContext sqlStatementContext = new
CursorHeldSQLStatementContext(closeStatement);
+ CursorConnectionContext cursorConnectionContext = new
CursorConnectionContext();
+ CursorStatementContext cursorStatementContext =
mock(CursorStatementContext.class, RETURNS_DEEP_STUBS);
+ cursorConnectionContext.getCursorStatementContexts().put("foo_cursor",
cursorStatementContext);
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext().getCursorContext()).thenReturn(cursorConnectionContext);
+ createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
+ assertThat(sqlStatementContext.getCursorStatementContext(),
is(cursorStatementContext));
+
assertFalse(cursorConnectionContext.getCursorStatementContexts().containsKey("foo_cursor"));
+ }
+
+ @Test
+ void assertConstructWithCursorStatementContext() {
+ CursorNameSegment cursorNameSegment = new CursorNameSegment(0, 0, new
IdentifierValue("foo_cursor"));
+ CursorStatement cursorStatement = new CursorStatement(databaseType,
cursorNameSegment, mock(SelectStatement.class));
+ cursorStatement.buildAttributes();
+ CursorStatementContext sqlStatementContext =
mock(CursorStatementContext.class, RETURNS_DEEP_STUBS);
+
when(sqlStatementContext.getSqlStatement()).thenReturn(cursorStatement);
+
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+
when(sqlStatementContext.getTablesContext().getSchemaNames()).thenReturn(Collections.emptyList());
+ CursorConnectionContext cursorConnectionContext = new
CursorConnectionContext();
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext().getCursorContext()).thenReturn(cursorConnectionContext);
+ createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
+
assertThat(cursorConnectionContext.getCursorStatementContexts().get("foo_cursor"),
is(sqlStatementContext));
+ }
+
+ @Test
+ void assertConstructWithSelectStatementContextWithoutDerivedProjections() {
+ SelectStatementContext sqlStatementContext =
mock(SelectStatementContext.class, RETURNS_DEEP_STUBS);
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ selectStatement.buildAttributes();
+
when(sqlStatementContext.getSqlStatement()).thenReturn(selectStatement);
+
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+
when(sqlStatementContext.getTablesContext().getSchemaNames()).thenReturn(Collections.emptyList());
+ assertNotNull(createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase())));
+ }
+
+ @Test
+ void assertExecuteWithFederation() throws SQLException {
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new SelectStatement(databaseType));
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ SQLFederationEngine sqlFederationEngine =
mock(SQLFederationEngine.class);
+
when(proxySQLExecutor.getSqlFederationEngine()).thenReturn(sqlFederationEngine);
+ when(sqlFederationEngine.decide(any(QueryContext.class),
any(RuleMetaData.class))).thenReturn(true);
+
when(databaseConnectionManager.getConnectionSession().getStatementManager()).thenReturn(mock(JDBCBackendStatement.class));
+ when(resultSet.getMetaData().getColumnCount()).thenReturn(1);
+ when(resultSet.getMetaData().getColumnName(1)).thenReturn("order_id");
+ when(resultSet.getMetaData().getColumnLabel(1)).thenReturn("order_id");
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ try (MockedStatic<DatabaseTypedSPILoader> spiLoader =
mockStatic(DatabaseTypedSPILoader.class)) {
+ when(sqlFederationEngine.executeQuery(any(), any(),
any())).thenAnswer(invocation -> {
+ setField(engine, "database", null);
+ return resultSet;
+ });
+ spiLoader.when(() ->
DatabaseTypedSPILoader.getService(eq(QueryHeaderBuilder.class),
any(DatabaseType.class))).thenReturn(new QueryHeaderBuilderFixture());
+ spiLoader.when(() ->
DatabaseTypedSPILoader.getService(QueryHeaderBuilder.class,
null)).thenReturn(new QueryHeaderBuilderFixture());
+ assertThat(engine.execute(),
instanceOf(QueryResponseHeader.class));
+ }
+ }
+
+ @Test
+ void assertExecuteWithFederationAndNotNullDatabase() throws SQLException {
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new SelectStatement(databaseType));
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ SQLFederationEngine sqlFederationEngine =
mock(SQLFederationEngine.class);
+
when(proxySQLExecutor.getSqlFederationEngine()).thenReturn(sqlFederationEngine);
+ when(sqlFederationEngine.decide(any(QueryContext.class),
any(RuleMetaData.class))).thenReturn(true);
+ when(sqlFederationEngine.executeQuery(any(), any(),
any())).thenReturn(resultSet);
+
when(databaseConnectionManager.getConnectionSession().getStatementManager()).thenReturn(mock(JDBCBackendStatement.class));
+ when(resultSet.getMetaData().getColumnCount()).thenReturn(1);
+ when(resultSet.getMetaData().getColumnName(1)).thenReturn("order_id");
+ when(resultSet.getMetaData().getColumnLabel(1)).thenReturn("order_id");
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ try (MockedStatic<DatabaseTypedSPILoader> spiLoader =
mockStatic(DatabaseTypedSPILoader.class)) {
+ spiLoader.when(() ->
DatabaseTypedSPILoader.getService(eq(QueryHeaderBuilder.class),
any(DatabaseType.class))).thenReturn(new QueryHeaderBuilderFixture());
+ assertThat(engine.execute(),
instanceOf(QueryResponseHeader.class));
+ }
+ }
+
+ @Test
+ void assertExecuteWithFederationEnabledAndNoRefresh() throws SQLException {
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new SQLStatement(databaseType));
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ SQLFederationEngine sqlFederationEngine =
mock(SQLFederationEngine.class);
+
when(proxySQLExecutor.getSqlFederationEngine()).thenReturn(sqlFederationEngine);
+ when(sqlFederationEngine.decide(any(QueryContext.class),
any(RuleMetaData.class))).thenReturn(false);
+ when(sqlFederationEngine.isSQLFederationEnabled()).thenReturn(true);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.emptyList());
+ try (
+ MockedConstruction<FederationMetaDataRefreshEngine>
mockedRefreshEngine = mockConstruction(FederationMetaDataRefreshEngine.class,
+ (mock, context) ->
when(mock.isNeedRefresh()).thenReturn(false));
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext))) {
+ assertThat(engine.execute(),
instanceOf(UpdateResponseHeader.class));
+ assertThat(mockedRefreshEngine.constructed().size(), is(1));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ }
+ }
+
+ @Test
+ void assertExecuteWithQueryResult() throws SQLException {
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new SQLStatement(databaseType));
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.singletonList(mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+ QueryResult queryResult = mock(QueryResult.class);
+ QueryResultMetaData queryResultMetaData =
mock(QueryResultMetaData.class);
+ when(queryResultMetaData.getColumnCount()).thenReturn(1);
+ when(queryResultMetaData.getColumnName(1)).thenReturn("order_id");
+ when(queryResultMetaData.getColumnLabel(1)).thenReturn("order_id");
+ when(queryResult.getMetaData()).thenReturn(queryResultMetaData);
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Collections.singletonList(queryResult));
+ MergedResult mergedResult = mock(MergedResult.class);
+ when(mergedResult.next()).thenReturn(true);
+ when(mergedResult.getValue(1, Object.class)).thenReturn(1);
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mock(DialectDatabaseMetaData.class);
+ DialectTransactionOption dialectTransactionOption =
mock(DialectTransactionOption.class);
+
when(dialectDatabaseMetaData.getTransactionOption()).thenReturn(dialectTransactionOption);
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(dialectDatabaseMetaData));
+ MockedConstruction<MergeEngine> mockedMergeEngine =
+ mockConstruction(MergeEngine.class, (mock, context) ->
when(mock.merge(anyList(), any(QueryContext.class))).thenReturn(mergedResult));
+ MockedStatic<DatabaseTypedSPILoader> spiLoader =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ spiLoader.when(() ->
DatabaseTypedSPILoader.getService(eq(QueryHeaderBuilder.class),
any(DatabaseType.class))).thenReturn(new QueryHeaderBuilderFixture());
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ assertThat(engine.execute(),
instanceOf(QueryResponseHeader.class));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ assertThat(mockedMergeEngine.constructed().size(), is(1));
+ assertTrue(engine.next());
+ assertNotNull(engine.getRowData());
+ }
+ }
+
+ @Test
+ void assertExecuteWithDerivedQueryResult() throws SQLException {
+ SelectStatementContext sqlStatementContext =
mock(SelectStatementContext.class, RETURNS_DEEP_STUBS);
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ selectStatement.buildAttributes();
+
when(sqlStatementContext.getSqlStatement()).thenReturn(selectStatement);
+
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+
when(sqlStatementContext.getTablesContext().getSchemaNames()).thenReturn(Collections.emptyList());
+
when(sqlStatementContext.containsDerivedProjections()).thenReturn(true);
+ Projection projection = mock(Projection.class);
+ when(projection.getColumnName()).thenReturn("order_id");
+ when(projection.getColumnLabel()).thenReturn("order_id");
+ ProjectionsContext projectionsContext = new ProjectionsContext(0, 0,
false, Collections.singleton(projection));
+
when(sqlStatementContext.getProjectionsContext()).thenReturn(projectionsContext);
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ SQLFederationEngine sqlFederationEngine =
mock(SQLFederationEngine.class);
+
when(proxySQLExecutor.getSqlFederationEngine()).thenReturn(sqlFederationEngine);
+ when(sqlFederationEngine.decide(any(QueryContext.class),
any(RuleMetaData.class))).thenReturn(false);
+ when(sqlFederationEngine.isSQLFederationEnabled()).thenReturn(false);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.singletonList(mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+ QueryResult queryResult = mock(QueryResult.class);
+
when(queryResult.getMetaData()).thenReturn(mock(QueryResultMetaData.class));
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Collections.singletonList(queryResult));
+ MergedResult mergedResult = mock(MergedResult.class);
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class)));
+ MockedConstruction<MergeEngine> mockedMergeEngine =
+ mockConstruction(MergeEngine.class, (mock, context) ->
when(mock.merge(anyList(), any(QueryContext.class))).thenReturn(mergedResult));
+ MockedStatic<DatabaseTypedSPILoader> spiLoader =
mockStatic(DatabaseTypedSPILoader.class);
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ spiLoader.when(() ->
DatabaseTypedSPILoader.getService(eq(QueryHeaderBuilder.class),
any(DatabaseType.class))).thenReturn(new QueryHeaderBuilderFixture());
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ assertThat(engine.execute(),
instanceOf(QueryResponseHeader.class));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ assertThat(mockedMergeEngine.constructed().size(), is(1));
+ }
+ }
+
+ @Test
+ void assertExecuteWithImplicitCommit() throws SQLException {
+ CloseStatement closeStatement = new CloseStatement(databaseType, null,
false);
+ closeStatement.buildAttributes();
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(closeStatement);
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.singletonList(mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Collections.singletonList(new
UpdateResult(1, 0L)));
+ DialectDatabaseMetaData dialectDatabaseMetaData =
mock(DialectDatabaseMetaData.class);
+ DialectTransactionOption dialectTransactionOption =
mock(DialectTransactionOption.class);
+
when(dialectDatabaseMetaData.getTransactionOption()).thenReturn(dialectTransactionOption);
+
when(dialectTransactionOption.isDDLNeedImplicitCommit()).thenReturn(true);
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(dialectDatabaseMetaData));
+ MockedConstruction<ProxyBackendTransactionManager>
mockedTransactionManager =
mockConstruction(ProxyBackendTransactionManager.class);
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ assertThat(engine.execute(),
instanceOf(UpdateResponseHeader.class));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+
verify(mockedTransactionManager.constructed().iterator().next()).commit();
+ }
+ }
+
+ @Test
+ void assertExecuteWithUpdateResultAndNoAccumulate() throws SQLException {
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(new InsertStatement(databaseType));
+
when(sqlStatementContext.getTablesContext().getTableNames()).thenReturn(Collections.singleton("t_order"));
+ ShardingSphereDatabase database = mockDatabase();
+
when(database.getRuleMetaData().getAttributes(DataNodeRuleAttribute.class)).thenReturn(Collections.singleton(mock(DataNodeRuleAttribute.class)));
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, database));
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class,
RETURNS_DEEP_STUBS);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.singletonList(mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Arrays.asList(new
UpdateResult(1, 4L), new UpdateResult(2, 5L)));
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class)));
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ UpdateResponseHeader actual = (UpdateResponseHeader)
engine.execute();
+ assertThat(actual.getUpdateCount(), is(1L));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ }
+ }
+
+ @Test
+ void assertExecuteWithoutImplicitCommitWhenSingleExecutionUnit() throws
SQLException {
+ InsertStatement insertStatement = new InsertStatement(databaseType);
+ assertThat(executeWithImplicitCommitCondition(insertStatement, "XA",
false, 1), instanceOf(UpdateResponseHeader.class));
+ }
+
+ @Test
+ void assertExecuteWithoutImplicitCommitWhenLocalTransaction() throws
SQLException {
+ InsertStatement insertStatement = new InsertStatement(databaseType);
+ assertThat(executeWithImplicitCommitCondition(insertStatement,
"LOCAL", false, 2), instanceOf(UpdateResponseHeader.class));
+ }
+
+ @Test
+ void assertExecuteWithoutImplicitCommitWhenAlreadyInTransaction() throws
SQLException {
+ InsertStatement insertStatement = new InsertStatement(databaseType);
+ assertThat(executeWithImplicitCommitCondition(insertStatement, "XA",
true, 2), instanceOf(UpdateResponseHeader.class));
+ }
+
+ @Test
+ void assertExecuteWithoutImplicitCommitWhenSelectStatement() throws
SQLException {
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ assertThat(executeWithImplicitCommitCondition(selectStatement, "XA",
false, 2), instanceOf(UpdateResponseHeader.class));
+ }
+
+ @Test
+ void assertExecuteWithoutImplicitCommitWhenSQLStatementIsNotDML() throws
SQLException {
+ SQLStatement sqlStatement = new SQLStatement(databaseType);
+ assertThat(executeWithImplicitCommitCondition(sqlStatement, "XA",
false, 2), instanceOf(UpdateResponseHeader.class));
+ }
+
+ @Test
+ void assertExecuteWithoutImplicitCommitForDDLWhenOptionDisabled() throws
SQLException {
+ CloseStatement closeStatement = new CloseStatement(databaseType, null,
false);
+ closeStatement.buildAttributes();
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(closeStatement);
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class);
+
when(executionContext.getExecutionUnits()).thenReturn(Collections.singletonList(mock(ExecutionUnit.class)));
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Collections.singletonList(new
UpdateResult(1, 0L)));
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class,
RETURNS_DEEP_STUBS)));
+ MockedConstruction<ProxyBackendTransactionManager>
mockedTransactionManager =
mockConstruction(ProxyBackendTransactionManager.class);
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ assertThat(engine.execute(),
instanceOf(UpdateResponseHeader.class));
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ assertTrue(mockedTransactionManager.constructed().isEmpty());
+ }
+ }
+
private DatabaseProxyConnector createDatabaseProxyConnector(final
JDBCDriverType driverType, final QueryContext queryContext) {
DatabaseProxyConnector result = new
StandardDatabaseProxyConnector(driverType, queryContext,
databaseConnectionManager);
databaseConnectionManager.add(result);
return result;
}
- private QueryContext createQueryContext(final SQLStatementContext
sqlStatementContext) {
+ private QueryContext createQueryContext(final SQLStatementContext
sqlStatementContext, final ShardingSphereDatabase database) {
ConnectionContext connectionContext = mock(ConnectionContext.class);
when(connectionContext.getCurrentDatabaseName()).thenReturn(Optional.of("foo_db"));
ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
when(metaData.containsDatabase("foo_db")).thenReturn(true);
- ShardingSphereDatabase database = mockDatabase();
when(metaData.getDatabase("foo_db")).thenReturn(database);
return new QueryContext(sqlStatementContext, "schemaName",
Collections.emptyList(), new HintValueContext(), connectionContext, metaData);
}
@@ -199,12 +730,40 @@ class StandardDatabaseProxyConnectorTest {
return result;
}
+ private ResponseHeader executeWithImplicitCommitCondition(final
SQLStatement sqlStatement, final String transactionType, final boolean
inTransaction,
+ final int
executionUnitCount) throws SQLException {
+
when(databaseConnectionManager.getConnectionSession().isAutoCommit()).thenReturn(true);
+
when(databaseConnectionManager.getConnectionSession().getConnectionContext().getTransactionContext().getTransactionType()).thenReturn(Optional.of(transactionType));
+
when(databaseConnectionManager.getConnectionSession().getTransactionStatus().isInTransaction()).thenReturn(inTransaction);
+ SQLStatementContext sqlStatementContext =
createSQLStatementContext(sqlStatement);
+ QueryContext queryContext = createQueryContext(sqlStatementContext,
mockDatabase());
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT, queryContext);
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class,
RETURNS_DEEP_STUBS);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ ExecutionContext executionContext = mock(ExecutionContext.class);
+
when(executionContext.getSqlStatementContext()).thenReturn(sqlStatementContext);
+
when(executionContext.getExecutionUnits()).thenReturn(IntStream.range(0,
executionUnitCount).mapToObj(index ->
mock(ExecutionUnit.class)).collect(Collectors.toList()));
+
when(proxySQLExecutor.execute(executionContext)).thenReturn(Collections.singletonList(new
UpdateResult(1, 0L)));
+ try (
+ MockedConstruction<KernelProcessor> mockedKernelProcessor =
mockConstruction(KernelProcessor.class,
+ (mock, context) ->
when(mock.generateExecutionContext(any(QueryContext.class),
any(RuleMetaData.class),
any(ConfigurationProperties.class))).thenReturn(executionContext));
+ MockedConstruction<DatabaseTypeRegistry>
mockedDatabaseTypeRegistry = mockConstruction(DatabaseTypeRegistry.class,
+ (mock, context) ->
when(mock.getDialectDatabaseMetaData()).thenReturn(mock(DialectDatabaseMetaData.class)));
+ MockedStatic<ShardingSphereServiceLoader> serviceLoader =
mockStatic(ShardingSphereServiceLoader.class)) {
+ serviceLoader.when(() ->
ShardingSphereServiceLoader.getServiceInstances(AdvancedProxySQLExecutor.class)).thenReturn(Collections.emptyList());
+ ResponseHeader result = engine.execute();
+ assertThat(mockedKernelProcessor.constructed().size(), is(1));
+ assertThat(mockedDatabaseTypeRegistry.constructed().size(), is(1));
+ return result;
+ }
+ }
+
@Test
void assertAddStatementCorrectly() {
SQLStatementContext sqlStatementContext =
mock(SQLStatementContext.class, RETURNS_DEEP_STUBS);
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
-
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
"FIXTURE"));
- DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext));
+
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
engine.add(statement);
Collection<?> actual = getField(engine, "cachedStatements");
assertThat(actual.size(), is(1));
@@ -215,8 +774,8 @@ class StandardDatabaseProxyConnectorTest {
void assertAddResultSetCorrectly() {
SQLStatementContext sqlStatementContext =
mock(SQLStatementContext.class, RETURNS_DEEP_STUBS);
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
-
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
"FIXTURE"));
- DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext));
+
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
engine.add(resultSet);
Collection<?> actual = getField(engine, "cachedResultSets");
assertThat(actual.size(), is(1));
@@ -227,8 +786,8 @@ class StandardDatabaseProxyConnectorTest {
void assertCloseCorrectly() throws SQLException {
SQLStatementContext sqlStatementContext =
mock(SQLStatementContext.class, RETURNS_DEEP_STUBS);
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
-
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
"FIXTURE"));
- DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext));
+
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
Collection<ResultSet> cachedResultSets = getField(engine,
"cachedResultSets");
cachedResultSets.add(resultSet);
Collection<Statement> cachedStatements = getField(engine,
"cachedStatements");
@@ -245,8 +804,8 @@ class StandardDatabaseProxyConnectorTest {
void assertCloseResultSetsWithExceptionThrown() throws SQLException {
SQLStatementContext sqlStatementContext =
mock(SQLStatementContext.class, RETURNS_DEEP_STUBS);
when(sqlStatementContext.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
-
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
"FIXTURE"));
- DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext));
+
when(sqlStatementContext.getSqlStatement().getDatabaseType()).thenReturn(databaseType);
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(sqlStatementContext, mockDatabase()));
Collection<ResultSet> cachedResultSets = getField(engine,
"cachedResultSets");
SQLException sqlExceptionByResultSet = new SQLException("ResultSet");
doThrow(sqlExceptionByResultSet).when(resultSet).close();
@@ -270,9 +829,82 @@ class StandardDatabaseProxyConnectorTest {
assertThat(actual.getNextException().getNextException(),
is(sqlExceptionByStatement));
}
+ @Test
+ void assertNext() throws SQLException {
+ assertFalse(createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
mockDatabase())).next());
+ }
+
+ @Test
+ void assertNextWithMergedResult() throws SQLException {
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
mockDatabase()));
+ MergedResult mergedResult = mock(MergedResult.class);
+ when(mergedResult.next()).thenReturn(true);
+ setField(engine, "mergedResult", mergedResult);
+ assertTrue(engine.next());
+ verify(mergedResult).next();
+ }
+
+ @Test
+ void assertNextWithMergedResultNoMoreData() throws SQLException {
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
mockDatabase()));
+ MergedResult mergedResult = mock(MergedResult.class);
+ when(mergedResult.next()).thenReturn(false);
+ setField(engine, "mergedResult", mergedResult);
+ assertFalse(engine.next());
+ verify(mergedResult).next();
+ }
+
+ @Test
+ void assertCloseWithSQLExceptionThrownBySQLFederationEngine() throws
SQLException {
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
mockDatabase()));
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class);
+ SQLFederationEngine sqlFederationEngine =
mock(SQLFederationEngine.class);
+
when(proxySQLExecutor.getSqlFederationEngine()).thenReturn(sqlFederationEngine);
+ SQLException expected = new SQLException("SQLFederationEngine");
+ doThrow(expected).when(sqlFederationEngine).close();
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ SQLException actual = null;
+ try {
+ engine.close();
+ } catch (final SQLException ex) {
+ actual = ex;
+ }
+ assertNotNull(actual);
+ assertThat(actual.getNextException(), is(expected));
+ verify(sqlFederationEngine).close();
+ }
+
+ @Test
+ void assertCloseWithNullSQLFederationEngine() throws SQLException {
+ DatabaseProxyConnector engine =
createDatabaseProxyConnector(JDBCDriverType.STATEMENT,
createQueryContext(createSQLStatementContext(new SQLStatement(databaseType)),
mockDatabase()));
+ ProxySQLExecutor proxySQLExecutor = mock(ProxySQLExecutor.class);
+ when(proxySQLExecutor.getSqlFederationEngine()).thenReturn(null);
+ setField(engine, "proxySQLExecutor", proxySQLExecutor);
+ engine.close();
+ Collection<?> cachedStatements = getField(engine, "cachedStatements");
+ Collection<?> cachedResultSets = getField(engine, "cachedResultSets");
+ assertTrue(cachedStatements.isEmpty());
+ assertTrue(cachedResultSets.isEmpty());
+ }
+
+ private SQLStatementContext createSQLStatementContext(final SQLStatement
sqlStatement) {
+ sqlStatement.buildAttributes();
+ SQLStatementContext result = mock(SQLStatementContext.class,
RETURNS_DEEP_STUBS);
+ when(result.getSqlStatement()).thenReturn(sqlStatement);
+
when(result.getTablesContext().getDatabaseNames()).thenReturn(Collections.emptyList());
+
when(result.getTablesContext().getSchemaNames()).thenReturn(Collections.emptyList());
+
when(result.getTablesContext().getTableNames()).thenReturn(Collections.emptyList());
+ return result;
+ }
+
@SuppressWarnings("unchecked")
@SneakyThrows(ReflectiveOperationException.class)
private <T> T getField(final DatabaseProxyConnector target, final String
fieldName) {
return (T)
Plugins.getMemberAccessor().get(StandardDatabaseProxyConnector.class.getDeclaredField(fieldName),
target);
}
+
+ @SneakyThrows(ReflectiveOperationException.class)
+ private void setField(final DatabaseProxyConnector target, final String
fieldName, final Object value) {
+
Plugins.getMemberAccessor().set(StandardDatabaseProxyConnector.class.getDeclaredField(fieldName),
target, value);
+ }
}