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 52fb1430ef5 Add proxy test cases (#37548)
52fb1430ef5 is described below
commit 52fb1430ef51b6ab05c128689b79f1256f78aa25
Author: Liang Zhang <[email protected]>
AuthorDate: Sat Dec 27 01:08:52 2025 +0800
Add proxy test cases (#37548)
---
AGENTS.md | 8 +-
.../executor/sysvar/MySQLSystemVariableTest.java | 80 +++++++++
.../MySQLSelectAdminExecutorFactoryTest.java | 105 ++++++++++++
...LSelectWithoutFromAdminExecutorFactoryTest.java | 181 +++++++++++++++++++++
...rontendChannelLimitationInboundHandlerTest.java | 107 ++++++++++++
.../frontend/state/ProxyStateContextTest.java | 94 +++++++++++
.../command/OpenGaussCommandExecuteEngine.java | 6 +-
.../command/OpenGaussCommandExecuteEngineTest.java | 116 +++++++++++++
8 files changed, 692 insertions(+), 5 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
index ace81a46650..57c32d013be 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -35,6 +35,8 @@ This guide is written **for AI coding agents only**. Follow
it literally; improv
- **Public-Only Tests**: unit tests must exercise behavior via public APIs
only; never use reflection to access private members.
- **Single-Test Naming**: when a production method is covered by only one test
case, name that test method `assert<MethodName>` without extra suffixes.
- **Public Method Isolation**: aim for one public production method per
dedicated test method rather than combining multiple public behaviors in a
single test.
+- **Test Method Order**: keep unit test method ordering consistent with
corresponding production methods when practical to improve traceability.
+- **Test Naming Simplicity**: keep test names concise and scenario-focused
(avoid “ReturnsXXX”/overly wordy or AI-like phrasing); describe the scenario
directly.
- **Coverage Pledge**: when 100% coverage is required, enumerate every
branch/path and its planned test before coding, then implement once to reach
100% without post-hoc fixes.
- **Mock/Spy Specification**: Use mock by default; consider spy only when the
scenario cannot be adequately represented using a mock. Avoid spy entirely when
standard `mock + when` can express behavior, and do not introduce inner classes
for testing purposes—prefer plain test classes with mocks.
- **Strictness and Stub Control**: Enable @MockitoSettings(strictness =
Strictness.LENIENT) in the Mockito scenario or apply lenient() to specific
stubs to ensure there are no unmatched or redundant stubs; clean up any unused
stubs, imports, or local variables before committing.
@@ -249,10 +251,12 @@ Always state which topology, registry, and engine
versions (e.g., MySQL 5.7 vs 8
- Favor Mockito over bespoke fixtures; only add new fixture classes when mocks
cannot express the scenario.
- Use marker interfaces when distinct rule/attribute types are needed; reuse
SPI types such as `ShardingSphereRule` where possible.
- Name tests after the production method under test; never probe private
helpers directly—document unreachable branches instead.
-- Mock heavy dependencies (database/cache/registry/network) and prefer mocking
over building deep object graphs; avoid `RETURNS_DEEP_STUBS` unless chained
interactions demand it.
+- Mock heavy dependencies (database/cache/registry/network) and prefer mocking
over building deep object graphs.
+- For static/constructor mocking, use `@ExtendWith(AutoMockExtension.class)`
with `@StaticMockSettings`; avoid hand-written `mockStatic`/`mockConstruction`
unless you documented why the extension cannot be used.
+- For deep chained interactions, you may use Mockito’s `RETURNS_DEEP_STUBS` to
reduce intermediate mocks; this is independent of the static-mock rule above.
- Before changing how mocks are created, scan the repository for similar tests
(e.g., other rule decorators or executor tests) and reuse their proven mocking
pattern instead of inventing a new structure.
- When constructors hide collaborators, use `Plugins.getMemberAccessor()` to
inject mocks and document why SPI creation is bypassed.
-- If a test already uses `@ExtendWith(AutoMockExtension.class)`, always
declare the needed static collaborators via `@StaticMockSettings` instead of
hand-written `mockStatic` blocks; when a class appears in
`@StaticMockSettings`, do not call `mockStatic` on it—directly stub via
`when(...)` (cast to `TypedSPI` if needed) to avoid ClassCast/duplicate-mock
issues; justify any exception explicitly in the plan before coding.
+- When static methods or constructors need mocking, prefer
`@ExtendWith(AutoMockExtension.class)` with `@StaticMockSettings` (or the
extension’s constructor-mocking support); when a class is listed in
`@StaticMockSettings`, do not call `mockStatic`/`mockConstruction`
directly—stub via `when(...)` instead. Only if AutoMockExtension cannot be used
and the reason is documented in the plan may you fall back to
`mockStatic`/`mockConstruction`, wrapped in try-with-resources.
- Before adding coverage to a utility with multiple return paths, list every
branch (no rule, non-Single config, wildcard blocks, missing data node,
positive path, collection overload) and map each to a test; update the plan
whenever this checklist changes.
- Prefer imports over fully-qualified class names inside code and tests; if a
class is used, add an import rather than using the full package path inline.
- Before coding tests, prepare a concise branch-and-data checklist (all
branches, inputs, expected outputs) and keep the plan in sync when the
checklist changes.
diff --git
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/MySQLSystemVariableTest.java
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/MySQLSystemVariableTest.java
new file mode 100644
index 00000000000..512fcf26d6d
--- /dev/null
+++
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/sysvar/MySQLSystemVariableTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.sysvar;
+
+import
org.apache.shardingsphere.database.exception.mysql.exception.ErrorGlobalVariableException;
+import
org.apache.shardingsphere.database.exception.mysql.exception.ErrorLocalVariableException;
+import
org.apache.shardingsphere.database.exception.mysql.exception.IncorrectGlobalLocalVariableException;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+
+class MySQLSystemVariableTest {
+
+ @Test
+ void assertFindSystemVariable() {
+
assertTrue(MySQLSystemVariable.findSystemVariable("max_connections").isPresent());
+
assertFalse(MySQLSystemVariable.findSystemVariable("non_exist").isPresent());
+ }
+
+ @Test
+ void assertGetValueForGlobalScope() {
+
assertThat(MySQLSystemVariable.ACTIVATE_ALL_ROLES_ON_LOGIN.getValue(MySQLSystemVariableScope.GLOBAL,
null), is("0"));
+ }
+
+ @Test
+ void assertGetValueRejectsGlobalForOnlySessionVariable() {
+ assertThrows(IncorrectGlobalLocalVariableException.class, () ->
MySQLSystemVariable.RAND_SEED1.getValue(MySQLSystemVariableScope.GLOBAL, null));
+ }
+
+ @Test
+ void assertGetValueForSessionScope() {
+
assertThat(MySQLSystemVariable.AUTOCOMMIT.getValue(MySQLSystemVariableScope.SESSION,
mock()), is("1"));
+ }
+
+ @Test
+ void assertGetValueRejectsSessionForGlobalOnlyVariable() {
+ assertThrows(IncorrectGlobalLocalVariableException.class, () ->
MySQLSystemVariable.ACTIVATE_ALL_ROLES_ON_LOGIN.getValue(MySQLSystemVariableScope.SESSION,
mock()));
+ }
+
+ @Test
+ void assertValidateSetTargetScopeRejectsGlobalForOnlySessionVariable() {
+ assertThrows(ErrorLocalVariableException.class, () ->
MySQLSystemVariable.RAND_SEED1.validateSetTargetScope(MySQLSystemVariableScope.GLOBAL));
+ }
+
+ @Test
+ void assertValidateSetTargetScopeRejectsSessionForGlobalVariable() {
+ assertThrows(ErrorGlobalVariableException.class, () ->
MySQLSystemVariable.ADMIN_ADDRESS.validateSetTargetScope(MySQLSystemVariableScope.SESSION));
+ }
+
+ @Test
+ void assertValidateSetTargetScopePassesForAllowedScope() {
+ assertDoesNotThrow(() ->
MySQLSystemVariable.AUTOCOMMIT.validateSetTargetScope(MySQLSystemVariableScope.SESSION));
+ }
+
+ @Test
+ void assertValidateSetTargetScopePassesForGlobalScope() {
+ assertDoesNotThrow(() ->
MySQLSystemVariable.ADMIN_ADDRESS.validateSetTargetScope(MySQLSystemVariableScope.GLOBAL));
+ }
+}
diff --git
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/MySQLSelectAdminExecutorFactoryTest.java
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/MySQLSelectAdminExecutorFactoryTest.java
new file mode 100644
index 00000000000..2cc630c8a94
--- /dev/null
+++
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/MySQLSelectAdminExecutorFactoryTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.backend.mysql.handler.admin.factory;
+
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import
org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.factory.schema.MySQLSystemSchemaQueryExecutorFactory;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.factory.withoutfrom.MySQLSelectWithoutFromAdminExecutorFactory;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Collections;
+import java.util.Optional;
+
+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.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings({MySQLSelectWithoutFromAdminExecutorFactory.class,
MySQLSystemSchemaQueryExecutorFactory.class})
+class MySQLSelectAdminExecutorFactoryTest {
+
+ private final DatabaseType databaseType =
TypedSPILoader.getService(DatabaseType.class, "MySQL");
+
+ @Test
+ void assertCreateWithoutFromUsesFactory() {
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ selectStatement.setProjections(new ProjectionsSegment(0, 0));
+ SelectStatementContext selectStatementContext =
mock(SelectStatementContext.class);
+
when(selectStatementContext.getSqlStatement()).thenReturn(selectStatement);
+ DatabaseAdminExecutor expected = mock(DatabaseAdminExecutor.class);
+ when(MySQLSelectWithoutFromAdminExecutorFactory.newInstance(any(),
any(), any(), any())).thenReturn(Optional.of(expected));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectAdminExecutorFactory.newInstance(selectStatementContext, "",
Collections.emptyList(), "db", mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), is(expected));
+ }
+
+ @Test
+ void assertCreateSystemSchemaExecutor() {
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ selectStatement.setProjections(new ProjectionsSegment(0, 0));
+ selectStatement.setFrom(mock(TableSegment.class));
+ SelectStatementContext selectStatementContext =
mock(SelectStatementContext.class);
+
when(selectStatementContext.getSqlStatement()).thenReturn(selectStatement);
+ DatabaseAdminExecutor expected = mock(DatabaseAdminExecutor.class);
+
when(MySQLSystemSchemaQueryExecutorFactory.newInstance(selectStatementContext,
"", Collections.emptyList(), "mysql")).thenReturn(Optional.of(expected));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectAdminExecutorFactory.newInstance(
+ selectStatementContext, "", Collections.emptyList(), "mysql",
mock(ShardingSphereMetaData.class, RETURNS_DEEP_STUBS));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), is(expected));
+ }
+
+ @Test
+ void assertSkipWhenSystemSchemaComplete() {
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ selectStatement.setProjections(new ProjectionsSegment(0, 0));
+ selectStatement.setFrom(mock(TableSegment.class));
+ SelectStatementContext selectStatementContext =
mock(SelectStatementContext.class);
+
when(selectStatementContext.getSqlStatement()).thenReturn(selectStatement);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(database.isComplete()).thenReturn(true);
+ ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
+ when(metaData.getDatabase("mysql")).thenReturn(database);
+
assertFalse(MySQLSelectAdminExecutorFactory.newInstance(selectStatementContext,
"", Collections.emptyList(), "mysql", metaData).isPresent());
+ }
+
+ @Test
+ void assertSkipWhenNonSystemSchema() {
+ SelectStatement selectStatement = new SelectStatement(databaseType);
+ selectStatement.setProjections(new ProjectionsSegment(0, 0));
+ selectStatement.setFrom(mock(TableSegment.class));
+ SelectStatementContext selectStatementContext =
mock(SelectStatementContext.class);
+
when(selectStatementContext.getSqlStatement()).thenReturn(selectStatement);
+
assertFalse(MySQLSelectAdminExecutorFactory.newInstance(selectStatementContext,
"", Collections.emptyList(), "test_db", mock()).isPresent());
+ }
+}
diff --git
a/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
new file mode 100644
index 00000000000..464da229b52
--- /dev/null
+++
b/proxy/backend/dialect/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/factory/withoutfrom/MySQLSelectWithoutFromAdminExecutorFactoryTest.java
@@ -0,0 +1,181 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.factory.withoutfrom;
+
+import
org.apache.shardingsphere.database.connector.mysql.type.MySQLDatabaseType;
+import
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
+import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData;
+import
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
+import
org.apache.shardingsphere.proxy.backend.handler.admin.executor.DatabaseAdminExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.MySQLSystemVariableQueryExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.select.NoResourceShowExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.select.ShowConnectionIdExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.select.ShowCurrentDatabaseExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.select.ShowCurrentUserExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.select.ShowVersionExecutor;
+import
org.apache.shardingsphere.proxy.backend.mysql.handler.admin.executor.select.UnicastResourceShowExecutor;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dal.VariableSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class MySQLSelectWithoutFromAdminExecutorFactoryTest {
+
+ @Test
+ void assertCreateSystemVariableExecutor() {
+ VariableSegment variableSegment = new VariableSegment(0, 0,
"max_connections");
+ ExpressionProjectionSegment projection = new
ExpressionProjectionSegment(0, 0, "@@max_connections", variableSegment);
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(projection));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(),
instanceOf(MySQLSystemVariableQueryExecutor.class));
+ }
+
+ @Test
+ void assertCreateShowConnectionIdExecutor() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0, "connection_id()")));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), instanceOf(ShowConnectionIdExecutor.class));
+ }
+
+ @Test
+ void assertCreateShowVersionExecutor() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0, "version()")));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), instanceOf(ShowVersionExecutor.class));
+ }
+
+ @Test
+ void assertCreateShowCurrentUserExecutor() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0,
ShowCurrentUserExecutor.FUNCTION_NAME_ALIAS)));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), instanceOf(ShowCurrentUserExecutor.class));
+ }
+
+ @Test
+ void assertCreateShowCurrentDatabaseExecutor() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0, "database()")));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(),
instanceOf(ShowCurrentDatabaseExecutor.class));
+ }
+
+ @Test
+ void assertCreateNoResourceExecutorWhenEmptyResource() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0, "other()")));
+ ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
+ when(metaData.getAllDatabases()).thenReturn(Collections.emptyList());
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
metaData);
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), instanceOf(NoResourceShowExecutor.class));
+ }
+
+ @Test
+ void assertReturnEmptyWhenMultipleProjectionsAndNoDatabase() {
+ ExpressionProjectionSegment firstProjection = new
ExpressionProjectionSegment(0, 0, "col1");
+ ExpressionProjectionSegment secondProjection = new
ExpressionProjectionSegment(0, 0, "col2");
+ SelectStatement selectStatement =
createSelectStatement(Arrays.asList(firstProjection, secondProjection));
+ ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(database.containsDataSource()).thenReturn(true);
+
when(metaData.getAllDatabases()).thenReturn(Collections.singletonList(database));
+
assertFalse(MySQLSelectWithoutFromAdminExecutorFactory.newInstance(mockSelectStatementContext(selectStatement),
"", null, metaData).isPresent());
+ }
+
+ @Test
+ void assertReturnEmptyWhenFirstProjectionIsNotExpression() {
+ ProjectionSegment shorthandProjection = mock(ProjectionSegment.class);
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(shorthandProjection));
+ ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(database.containsDataSource()).thenReturn(true);
+
when(metaData.getAllDatabases()).thenReturn(Collections.singletonList(database));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(mockSelectStatementContext(selectStatement),
"", null, metaData);
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(),
instanceOf(UnicastResourceShowExecutor.class));
+ }
+
+ @Test
+ void assertReturnEmptyWhenDatabaseSpecified() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0, "col1")));
+ ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(database.containsDataSource()).thenReturn(true);
+
when(metaData.getAllDatabases()).thenReturn(Collections.singletonList(database));
+
assertFalse(MySQLSelectWithoutFromAdminExecutorFactory.newInstance(mockSelectStatementContext(selectStatement),
"", "logic_db", metaData).isPresent());
+ }
+
+ @Test
+ void assertCreateUnicastResourceShowExecutor() {
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(new
ExpressionProjectionSegment(0, 0, "col1")));
+ ShardingSphereMetaData metaData = mock(ShardingSphereMetaData.class);
+ ShardingSphereDatabase database = mock(ShardingSphereDatabase.class);
+ when(database.containsDataSource()).thenReturn(true);
+
when(metaData.getAllDatabases()).thenReturn(Collections.singletonList(database));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
metaData);
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(),
instanceOf(UnicastResourceShowExecutor.class));
+ }
+
+ @Test
+ void assertCreateShowCurrentUserExecutorWithAliasName() {
+ ExpressionProjectionSegment projection = new
ExpressionProjectionSegment(0, 0, "current_user");
+ SelectStatement selectStatement =
createSelectStatement(Collections.singletonList(projection));
+ Optional<DatabaseAdminExecutor> actual =
MySQLSelectWithoutFromAdminExecutorFactory.newInstance(
+ mockSelectStatementContext(selectStatement), "", null,
mock(ShardingSphereMetaData.class));
+ assertTrue(actual.isPresent());
+ assertThat(actual.get(), instanceOf(ShowCurrentUserExecutor.class));
+ }
+
+ private SelectStatement createSelectStatement(final
Iterable<ProjectionSegment> projections) {
+ SelectStatement result = new SelectStatement(new MySQLDatabaseType());
+ ProjectionsSegment projectionsSegment = new ProjectionsSegment(0, 0);
+ projections.forEach(projectionsSegment.getProjections()::add);
+ result.setProjections(projectionsSegment);
+ return result;
+ }
+
+ private SelectStatementContext mockSelectStatementContext(final
SelectStatement selectStatement) {
+ SelectStatementContext result = mock(SelectStatementContext.class);
+ when(result.getSqlStatement()).thenReturn(selectStatement);
+ return result;
+ }
+}
diff --git
a/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelLimitationInboundHandlerTest.java
b/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelLimitationInboundHandlerTest.java
new file mode 100644
index 00000000000..cf4bbe95341
--- /dev/null
+++
b/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelLimitationInboundHandlerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.frontend.netty;
+
+import io.netty.channel.ChannelConfig;
+import io.netty.channel.ChannelHandlerContext;
+import lombok.SneakyThrows;
+import
org.apache.shardingsphere.database.exception.core.exception.connection.TooManyConnectionsException;
+import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
+import org.apache.shardingsphere.infra.config.props.ConfigurationPropertyKey;
+import org.apache.shardingsphere.mode.manager.ContextManager;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import
org.apache.shardingsphere.proxy.frontend.connection.ConnectionLimitContext;
+import
org.apache.shardingsphere.proxy.frontend.spi.DatabaseProtocolFrontendEngine;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.internal.configuration.plugins.Plugins;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ProxyContext.class)
+class FrontendChannelLimitationInboundHandlerTest {
+
+ @BeforeEach
+ void resetActiveConnections() {
+ getActiveConnectionsCounter().set(0);
+ }
+
+ @SneakyThrows(ReflectiveOperationException.class)
+ private AtomicInteger getActiveConnectionsCounter() {
+ return (AtomicInteger)
Plugins.getMemberAccessor().get(ConnectionLimitContext.class.getDeclaredField("activeConnections"),
ConnectionLimitContext.getInstance());
+ }
+
+ @Test
+ void assertChannelActiveWhenAllowed() {
+ mockMaxConnections(2);
+ DatabaseProtocolFrontendEngine frontendEngine =
mock(DatabaseProtocolFrontendEngine.class);
+ FrontendChannelLimitationInboundHandler handler = new
FrontendChannelLimitationInboundHandler(frontendEngine);
+ ChannelHandlerContext context = mockChannelHandlerContext();
+ handler.channelActive(context);
+ verify(context).fireChannelActive();
+ }
+
+ @Test
+ void assertChannelActiveRejected() {
+ mockMaxConnections(1);
+ DatabaseProtocolFrontendEngine frontendEngine =
mock(DatabaseProtocolFrontendEngine.class, RETURNS_DEEP_STUBS);
+ DatabasePacket errorPacket = mock(DatabasePacket.class);
+
when(frontendEngine.getCommandExecuteEngine().getErrorPacket(any(TooManyConnectionsException.class))).thenReturn(errorPacket);
+ FrontendChannelLimitationInboundHandler handler = new
FrontendChannelLimitationInboundHandler(frontendEngine);
+ ChannelHandlerContext context = mockChannelHandlerContext();
+ ConnectionLimitContext.getInstance().connectionAllowed();
+ handler.channelActive(context);
+ verify(context).writeAndFlush(errorPacket);
+ verify(context).close();
+ }
+
+ @Test
+ void assertChannelInactiveReleasesConnection() {
+ mockMaxConnections(1);
+ ConnectionLimitContext.getInstance().connectionAllowed();
+ ChannelHandlerContext context = mockChannelHandlerContext();
+ new
FrontendChannelLimitationInboundHandler(mock()).channelInactive(context);
+ verify(context).fireChannelInactive();
+ assertThat(getActiveConnectionsCounter().get(), is(0));
+ }
+
+ private void mockMaxConnections(final int maxConnections) {
+ ContextManager contextManager = mock(ContextManager.class,
RETURNS_DEEP_STUBS);
+
when(contextManager.getMetaDataContexts().getMetaData().getProps().getValue(ConfigurationPropertyKey.PROXY_FRONTEND_MAX_CONNECTIONS)).thenReturn(maxConnections);
+
when(ProxyContext.getInstance().getContextManager()).thenReturn(contextManager);
+ }
+
+ private ChannelHandlerContext mockChannelHandlerContext() {
+ ChannelHandlerContext result = mock(ChannelHandlerContext.class,
RETURNS_DEEP_STUBS);
+ ChannelConfig config = result.channel().config();
+ when(config.setAutoRead(false)).thenReturn(config);
+ return result;
+ }
+}
diff --git
a/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/state/ProxyStateContextTest.java
b/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/state/ProxyStateContextTest.java
new file mode 100644
index 00000000000..985c1bd6ab8
--- /dev/null
+++
b/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/state/ProxyStateContextTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.frontend.state;
+
+import io.netty.channel.ChannelHandlerContext;
+import lombok.SneakyThrows;
+import org.apache.shardingsphere.infra.state.instance.InstanceState;
+import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.frontend.spi.DatabaseProtocolFrontendEngine;
+import
org.apache.shardingsphere.proxy.frontend.state.impl.CircuitBreakProxyState;
+import org.apache.shardingsphere.proxy.frontend.state.impl.OKProxyState;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.MockedConstruction;
+import org.mockito.internal.configuration.plugins.Plugins;
+
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ProxyContext.class)
+class ProxyStateContextTest {
+
+ @Test
+ void assertExecuteWithOKState() {
+ try (
+ MockedConstruction<OKProxyState> ignoredOkStateConstruction =
mockConstruction(OKProxyState.class);
+ MockedConstruction<CircuitBreakProxyState>
ignoredCircuitBreakConstruction =
mockConstruction(CircuitBreakProxyState.class)) {
+
when(ProxyContext.getInstance().getContextManager().getComputeNodeInstanceContext().getInstance().getState().getCurrentState()).thenReturn(InstanceState.OK);
+ ProxyState okState = new OKProxyState();
+ ProxyState circuitBreakState = new CircuitBreakProxyState();
+ replaceStates(okState, circuitBreakState);
+ ChannelHandlerContext context = mock(ChannelHandlerContext.class);
+ Object message = new Object();
+ DatabaseProtocolFrontendEngine frontendEngine =
mock(DatabaseProtocolFrontendEngine.class);
+ ConnectionSession connectionSession =
mock(ConnectionSession.class);
+ ProxyStateContext.execute(context, message, frontendEngine,
connectionSession);
+ verify(okState).execute(context, message, frontendEngine,
connectionSession);
+ }
+ }
+
+ @Test
+ void assertExecuteWithCircuitBreakState() {
+ try (
+ MockedConstruction<OKProxyState> ignoredOkStateConstruction =
mockConstruction(OKProxyState.class);
+ MockedConstruction<CircuitBreakProxyState>
ignoredCircuitBreakConstruction =
mockConstruction(CircuitBreakProxyState.class)) {
+
when(ProxyContext.getInstance().getContextManager().getComputeNodeInstanceContext().getInstance().getState().getCurrentState()).thenReturn(InstanceState.CIRCUIT_BREAK);
+ ProxyState okState = new OKProxyState();
+ ProxyState circuitBreakState = new CircuitBreakProxyState();
+ replaceStates(okState, circuitBreakState);
+ ChannelHandlerContext context = mock(ChannelHandlerContext.class);
+ Object message = new Object();
+ DatabaseProtocolFrontendEngine frontendEngine =
mock(DatabaseProtocolFrontendEngine.class);
+ ConnectionSession connectionSession =
mock(ConnectionSession.class);
+ ProxyStateContext.execute(context, message, frontendEngine,
connectionSession);
+ verify(circuitBreakState).execute(context, message,
frontendEngine, connectionSession);
+ }
+ }
+
+ private void replaceStates(final ProxyState okState, final ProxyState
circuitBreakState) {
+ Map<InstanceState, ProxyState> states = getStates();
+ states.clear();
+ states.put(InstanceState.OK, okState);
+ states.put(InstanceState.CIRCUIT_BREAK, circuitBreakState);
+ }
+
+ @SuppressWarnings("unchecked")
+ @SneakyThrows(ReflectiveOperationException.class)
+ private Map<InstanceState, ProxyState> getStates() {
+ return (Map<InstanceState, ProxyState>)
Plugins.getMemberAccessor().get(ProxyStateContext.class.getDeclaredField("STATES"),
null);
+ }
+}
diff --git
a/proxy/frontend/dialect/opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngine.java
b/proxy/frontend/dialect/opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngine.java
index 9ad007d599a..3f27fbed282 100644
---
a/proxy/frontend/dialect/opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngine.java
+++
b/proxy/frontend/dialect/opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngine.java
@@ -45,7 +45,7 @@ import java.util.Optional;
*/
public final class OpenGaussCommandExecuteEngine implements
CommandExecuteEngine {
- private final PostgreSQLCommandExecuteEngine
postgresqlCommandExecuteEngine = new PostgreSQLCommandExecuteEngine();
+ private final PostgreSQLCommandExecuteEngine delegated = new
PostgreSQLCommandExecuteEngine();
@Override
public CommandPacketType getCommandPacketType(final PacketPayload payload)
{
@@ -70,12 +70,12 @@ public final class OpenGaussCommandExecuteEngine implements
CommandExecuteEngine
@Override
public Optional<DatabasePacket> getOtherPacket(final ConnectionSession
connectionSession) {
- return
postgresqlCommandExecuteEngine.getOtherPacket(connectionSession);
+ return delegated.getOtherPacket(connectionSession);
}
@Override
public void writeQueryData(final ChannelHandlerContext context,
final ProxyDatabaseConnectionManager
databaseConnectionManager, final QueryCommandExecutor queryCommandExecutor,
final int headerPackagesCount) throws SQLException {
- postgresqlCommandExecuteEngine.writeQueryData(context,
databaseConnectionManager, queryCommandExecutor, headerPackagesCount);
+ delegated.writeQueryData(context, databaseConnectionManager,
queryCommandExecutor, headerPackagesCount);
}
}
diff --git
a/proxy/frontend/dialect/opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngineTest.java
b/proxy/frontend/dialect/opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngineTest.java
new file mode 100644
index 00000000000..6dad0691e74
--- /dev/null
+++
b/proxy/frontend/dialect/opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/command/OpenGaussCommandExecuteEngineTest.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.proxy.frontend.opengauss.command;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import
org.apache.shardingsphere.database.protocol.opengauss.packet.command.OpenGaussCommandPacketFactory;
+import
org.apache.shardingsphere.database.protocol.opengauss.packet.command.OpenGaussCommandPacketType;
+import
org.apache.shardingsphere.database.protocol.opengauss.packet.command.generic.OpenGaussErrorResponsePacket;
+import org.apache.shardingsphere.database.protocol.payload.PacketPayload;
+import
org.apache.shardingsphere.database.protocol.postgresql.packet.command.PostgreSQLCommandPacket;
+import
org.apache.shardingsphere.database.protocol.postgresql.payload.PostgreSQLPacketPayload;
+import
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
+import
org.apache.shardingsphere.proxy.frontend.command.executor.CommandExecutor;
+import
org.apache.shardingsphere.proxy.frontend.command.executor.QueryCommandExecutor;
+import
org.apache.shardingsphere.proxy.frontend.opengauss.err.OpenGaussErrorPacketFactory;
+import
org.apache.shardingsphere.proxy.frontend.postgresql.command.PostgreSQLCommandExecuteEngine;
+import
org.apache.shardingsphere.proxy.frontend.postgresql.command.PostgreSQLPortalContextRegistry;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.internal.configuration.plugins.Plugins;
+
+import java.sql.SQLException;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings({OpenGaussCommandPacketFactory.class,
OpenGaussCommandExecutorFactory.class, OpenGaussErrorPacketFactory.class,
PostgreSQLPortalContextRegistry.class})
+class OpenGaussCommandExecuteEngineTest {
+
+ private final OpenGaussCommandExecuteEngine engine = new
OpenGaussCommandExecuteEngine();
+
+ @Mock
+ private PostgreSQLCommandExecuteEngine delegated;
+
+ @BeforeEach
+ void setUp() throws ReflectiveOperationException {
+
Plugins.getMemberAccessor().set(OpenGaussCommandExecuteEngine.class.getDeclaredField("delegated"),
engine, delegated);
+ }
+
+ @Test
+ void assertGetCommandPacketType() {
+ ByteBuf byteBuf = Unpooled.buffer();
+
byteBuf.writeByte(OpenGaussCommandPacketType.BATCH_BIND_COMMAND.getValue());
+ PacketPayload payload = mock(PacketPayload.class, RETURNS_DEEP_STUBS);
+ when(payload.getByteBuf()).thenReturn(byteBuf);
+ assertThat(engine.getCommandPacketType(payload),
is(OpenGaussCommandPacketType.BATCH_BIND_COMMAND));
+ }
+
+ @Test
+ void assertGetCommandPacket() {
+ PostgreSQLCommandPacket expectedPacket =
mock(PostgreSQLCommandPacket.class);
+ when(OpenGaussCommandPacketFactory.newInstance(any(),
any(PostgreSQLPacketPayload.class))).thenReturn(expectedPacket);
+
assertThat(engine.getCommandPacket(mock(PostgreSQLPacketPayload.class),
OpenGaussCommandPacketType.BATCH_BIND_COMMAND, mock(ConnectionSession.class)),
is(expectedPacket));
+ }
+
+ @Test
+ void assertGetCommandExecutor() throws SQLException {
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ when(connectionSession.getConnectionId()).thenReturn(1);
+ CommandExecutor expectedExecutor = mock(CommandExecutor.class);
+
when(PostgreSQLPortalContextRegistry.getInstance()).thenReturn(mock(PostgreSQLPortalContextRegistry.class));
+ when(OpenGaussCommandExecutorFactory.newInstance(any(),
any(PostgreSQLCommandPacket.class), any(), any())).thenReturn(expectedExecutor);
+
assertThat(engine.getCommandExecutor(OpenGaussCommandPacketType.BATCH_BIND_COMMAND,
mock(PostgreSQLCommandPacket.class), connectionSession), is(expectedExecutor));
+ }
+
+ @Test
+ void assertGetErrorPacket() {
+ OpenGaussErrorResponsePacket expectedPacket =
mock(OpenGaussErrorResponsePacket.class);
+
when(OpenGaussErrorPacketFactory.newInstance(any(Exception.class))).thenReturn(expectedPacket);
+ assertThat(engine.getErrorPacket(new Exception("err")),
is(expectedPacket));
+ }
+
+ @Test
+ void assertGetOtherPacket() {
+ ConnectionSession connectionSession = mock(ConnectionSession.class);
+ engine.getOtherPacket(connectionSession);
+ verify(delegated).getOtherPacket(connectionSession);
+ }
+
+ @Test
+ void assertWriteQueryData() throws SQLException {
+ ChannelHandlerContext context = mock(ChannelHandlerContext.class);
+ ProxyDatabaseConnectionManager databaseConnectionManager =
mock(ProxyDatabaseConnectionManager.class);
+ QueryCommandExecutor queryCommandExecutor =
mock(QueryCommandExecutor.class);
+ engine.writeQueryData(context, databaseConnectionManager,
queryCommandExecutor, 1);
+ verify(delegated).writeQueryData(context, databaseConnectionManager,
queryCommandExecutor, 1);
+ }
+}