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 b7f9685c42c Add more test cases on FrontendChannelInboundHandlerTest 
(#37892)
b7f9685c42c is described below

commit b7f9685c42c3e3f0229a0a4ce5d8afbd12e53aa3
Author: Liang Zhang <[email protected]>
AuthorDate: Fri Jan 30 00:41:09 2026 +0800

    Add more test cases on FrontendChannelInboundHandlerTest (#37892)
    
    * Add ignore pattern on dead links check
    
    * Add more test cases on FrontendChannelInboundHandlerTest
---
 .../netty/FrontendChannelInboundHandlerTest.java   | 168 ++++++++++++++++++++-
 1 file changed, 167 insertions(+), 1 deletion(-)

diff --git 
a/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelInboundHandlerTest.java
 
b/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelInboundHandlerTest.java
index d6b7ebc4758..549fb9cacb6 100644
--- 
a/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelInboundHandlerTest.java
+++ 
b/proxy/frontend/core/src/test/java/org/apache/shardingsphere/proxy/frontend/netty/FrontendChannelInboundHandlerTest.java
@@ -17,7 +17,9 @@
 
 package org.apache.shardingsphere.proxy.frontend.netty;
 
+import com.google.common.util.concurrent.MoreExecutors;
 import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.embedded.EmbeddedChannel;
 import lombok.SneakyThrows;
@@ -25,16 +27,24 @@ import 
org.apache.shardingsphere.authentication.result.AuthenticationResult;
 import 
org.apache.shardingsphere.authentication.result.AuthenticationResultBuilder;
 import org.apache.shardingsphere.authority.rule.AuthorityRule;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import 
org.apache.shardingsphere.database.exception.core.exception.SQLDialectException;
 import org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
 import org.apache.shardingsphere.database.protocol.payload.PacketPayload;
+import org.apache.shardingsphere.infra.executor.sql.process.ProcessEngine;
 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
 import org.apache.shardingsphere.infra.metadata.user.Grantee;
 import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.mode.manager.ContextManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.ProxyDatabaseConnectionManager;
+import 
org.apache.shardingsphere.proxy.backend.connector.jdbc.connection.ConnectionResourceLock;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import org.apache.shardingsphere.proxy.backend.session.ConnectionSession;
 import 
org.apache.shardingsphere.proxy.frontend.authentication.AuthenticationEngine;
+import org.apache.shardingsphere.proxy.frontend.exception.ExpectedExceptions;
+import 
org.apache.shardingsphere.proxy.frontend.executor.ConnectionThreadExecutorGroup;
+import org.apache.shardingsphere.proxy.frontend.executor.UserExecutorGroup;
 import 
org.apache.shardingsphere.proxy.frontend.spi.DatabaseProtocolFrontendEngine;
+import org.apache.shardingsphere.proxy.frontend.state.ProxyStateContext;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
 import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
 import org.apache.shardingsphere.transaction.rule.TransactionRule;
@@ -43,16 +53,28 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Answers;
 import org.mockito.Mock;
+import org.mockito.MockedStatic;
 import org.mockito.internal.configuration.plugins.Plugins;
 
+import java.sql.SQLException;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 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.assertNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -78,7 +100,7 @@ class FrontendChannelInboundHandlerTest {
     void setup() {
         
when(frontendEngine.getAuthenticationEngine()).thenReturn(authenticationEngine);
         
when(frontendEngine.getType()).thenReturn(TypedSPILoader.getService(DatabaseType.class,
 "MySQL"));
-        
when(authenticationEngine.handshake(any(ChannelHandlerContext.class))).thenReturn(CONNECTION_ID);
+        
lenient().when(authenticationEngine.handshake(any(ChannelHandlerContext.class))).thenReturn(CONNECTION_ID);
         channel = new EmbeddedChannel(false, true);
         ContextManager contextManager = mock(ContextManager.class, 
RETURNS_DEEP_STUBS);
         
when(contextManager.getMetaDataContexts().getMetaData().getGlobalRuleMetaData()).thenReturn(new
 RuleMetaData(Arrays.asList(mock(TransactionRule.class), 
mock(AuthorityRule.class))));
@@ -110,6 +132,40 @@ class FrontendChannelInboundHandlerTest {
         assertThat(connectionSession.getUsedDatabaseName(), is("database"));
     }
     
+    @Test
+    void assertChannelReadWithUnfinishedAuthentication() throws Exception {
+        channel.register();
+        
when(authenticationEngine.authenticate(any(ChannelHandlerContext.class), 
any(PacketPayload.class))).thenReturn(AuthenticationResultBuilder.continued());
+        channel.writeInbound(Unpooled.EMPTY_BUFFER);
+        assertFalse(getAuthenticated().get());
+        assertNull(connectionSession.getConnectionContext());
+    }
+    
+    @Test
+    void assertChannelReadWhenAuthenticated() throws Exception {
+        channel.register();
+        getAuthenticated().set(true);
+        Object message = new Object();
+        ChannelHandlerContext context = 
channel.pipeline().context(frontendChannelInboundHandler);
+        try (MockedStatic<ProxyStateContext> mockedStatic = 
mockStatic(ProxyStateContext.class)) {
+            channel.writeInbound(message);
+            mockedStatic.verify(() -> ProxyStateContext.execute(context, 
message, frontendEngine, connectionSession));
+        }
+    }
+    
+    @Test
+    void assertChannelReadWithExpectedException() throws Exception {
+        channel.register();
+        SQLDialectException cause = new 
SQLDialectException("assertChannelReadWithExpectedException") {
+        };
+        
doThrow(cause).when(authenticationEngine).authenticate(any(ChannelHandlerContext.class),
 any(PacketPayload.class));
+        DatabasePacket expectedPacket = mock(DatabasePacket.class);
+        
when(frontendEngine.getCommandExecuteEngine().getErrorPacket(cause)).thenReturn(expectedPacket);
+        channel.writeInbound(Unpooled.EMPTY_BUFFER);
+        assertThat(channel.readOutbound(), is(expectedPacket));
+        assertFalse(channel.isActive());
+    }
+    
     @Test
     void assertChannelReadNotAuthenticatedAndExceptionOccur() throws Exception 
{
         channel.register();
@@ -120,4 +176,114 @@ class FrontendChannelInboundHandlerTest {
         channel.writeInbound(Unpooled.EMPTY_BUFFER);
         assertThat(channel.readOutbound(), is(expectedPacket));
     }
+    
+    @Test
+    void assertChannelInactiveWithUnexpectedException() throws Exception {
+        ProxyDatabaseConnectionManager databaseConnectionManager = 
mock(ProxyDatabaseConnectionManager.class);
+        
when(databaseConnectionManager.closeAllResources()).thenReturn(Collections.singleton(new
 SQLException("assertChannelInactiveWithUnexpectedException")));
+        setDatabaseConnectionManager(databaseConnectionManager);
+        ProcessEngine processEngine = mock(ProcessEngine.class);
+        setProcessEngine(processEngine);
+        connectionSession.setProcessId("process-id");
+        ExecutorService executorService = 
MoreExecutors.newDirectExecutorService();
+        UserExecutorGroup userExecutorGroup = mock(UserExecutorGroup.class);
+        
when(userExecutorGroup.getExecutorService()).thenReturn(executorService);
+        ConnectionThreadExecutorGroup connectionThreadExecutorGroup = 
mock(ConnectionThreadExecutorGroup.class);
+        try (
+                MockedStatic<UserExecutorGroup> mockedUserExecutorGroup = 
mockStatic(UserExecutorGroup.class);
+                MockedStatic<ConnectionThreadExecutorGroup> 
mockedConnectionThreadExecutorGroup = 
mockStatic(ConnectionThreadExecutorGroup.class)) {
+            
mockedUserExecutorGroup.when(UserExecutorGroup::getInstance).thenReturn(userExecutorGroup);
+            
mockedConnectionThreadExecutorGroup.when(ConnectionThreadExecutorGroup::getInstance).thenReturn(connectionThreadExecutorGroup);
+            channel.register();
+            channel.pipeline().fireChannelInactive();
+            
verify(connectionThreadExecutorGroup).unregisterAndAwaitTermination(CONNECTION_ID);
+            verify(databaseConnectionManager).closeAllResources();
+            verify(processEngine).disconnect("process-id");
+            verify(frontendEngine).release(connectionSession);
+        }
+        executorService.shutdownNow();
+    }
+    
+    @Test
+    void assertChannelInactiveWithExpectedException() throws Exception {
+        Collection<Class<? extends Exception>> originalExpectedExceptions = 
new HashSet<>(getExpectedExceptions());
+        Collection<Class<? extends Exception>> expectedExceptions = 
getExpectedExceptions();
+        expectedExceptions.add(SQLException.class);
+        try {
+            ProxyDatabaseConnectionManager databaseConnectionManager = 
mock(ProxyDatabaseConnectionManager.class);
+            
when(databaseConnectionManager.closeAllResources()).thenReturn(Collections.singleton(new
 SQLException("assertChannelInactiveWithExpectedException")));
+            setDatabaseConnectionManager(databaseConnectionManager);
+            ExecutorService executorService = 
MoreExecutors.newDirectExecutorService();
+            UserExecutorGroup userExecutorGroup = 
mock(UserExecutorGroup.class);
+            
when(userExecutorGroup.getExecutorService()).thenReturn(executorService);
+            ConnectionThreadExecutorGroup connectionThreadExecutorGroup = 
mock(ConnectionThreadExecutorGroup.class);
+            try (
+                    MockedStatic<UserExecutorGroup> mockedUserExecutorGroup = 
mockStatic(UserExecutorGroup.class);
+                    MockedStatic<ConnectionThreadExecutorGroup> 
mockedConnectionThreadExecutorGroup = 
mockStatic(ConnectionThreadExecutorGroup.class)) {
+                
mockedUserExecutorGroup.when(UserExecutorGroup::getInstance).thenReturn(userExecutorGroup);
+                
mockedConnectionThreadExecutorGroup.when(ConnectionThreadExecutorGroup::getInstance).thenReturn(connectionThreadExecutorGroup);
+                channel.register();
+                channel.pipeline().fireChannelInactive();
+                
verify(connectionThreadExecutorGroup).unregisterAndAwaitTermination(CONNECTION_ID);
+                verify(databaseConnectionManager).closeAllResources();
+                verify(frontendEngine).release(connectionSession);
+            }
+            executorService.shutdownNow();
+        } finally {
+            Collection<Class<? extends Exception>> expectedExceptionClasses = 
getExpectedExceptions();
+            expectedExceptionClasses.clear();
+            expectedExceptionClasses.addAll(originalExpectedExceptions);
+        }
+    }
+    
+    @Test
+    void assertChannelWritabilityChangedWhenWritable() throws Exception {
+        ProxyDatabaseConnectionManager databaseConnectionManager = 
mock(ProxyDatabaseConnectionManager.class);
+        ConnectionResourceLock connectionResourceLock = 
mock(ConnectionResourceLock.class);
+        
when(databaseConnectionManager.getConnectionResourceLock()).thenReturn(connectionResourceLock);
+        channel.register();
+        setDatabaseConnectionManager(databaseConnectionManager);
+        assertThat(connectionSession.getDatabaseConnectionManager(), 
is(databaseConnectionManager));
+        Channel channelMock = mock(Channel.class);
+        ChannelHandlerContext context = mock(ChannelHandlerContext.class);
+        when(channelMock.isWritable()).thenReturn(true);
+        when(context.channel()).thenReturn(channelMock);
+        frontendChannelInboundHandler.channelWritabilityChanged(context);
+        verify(connectionResourceLock).doNotify();
+    }
+    
+    @Test
+    void assertChannelWritabilityChangedWhenNotWritable() throws Exception {
+        ProxyDatabaseConnectionManager databaseConnectionManager = 
mock(ProxyDatabaseConnectionManager.class);
+        channel.register();
+        setDatabaseConnectionManager(databaseConnectionManager);
+        assertThat(connectionSession.getDatabaseConnectionManager(), 
is(databaseConnectionManager));
+        Channel channelMock = mock(Channel.class);
+        ChannelHandlerContext context = mock(ChannelHandlerContext.class);
+        when(channelMock.isWritable()).thenReturn(false);
+        when(context.channel()).thenReturn(channelMock);
+        frontendChannelInboundHandler.channelWritabilityChanged(context);
+        verify(databaseConnectionManager, never()).getConnectionResourceLock();
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private AtomicBoolean getAuthenticated() {
+        return (AtomicBoolean) 
Plugins.getMemberAccessor().get(FrontendChannelInboundHandler.class.getDeclaredField("authenticated"),
 frontendChannelInboundHandler);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private void setDatabaseConnectionManager(final 
ProxyDatabaseConnectionManager databaseConnectionManager) {
+        
Plugins.getMemberAccessor().set(ConnectionSession.class.getDeclaredField("databaseConnectionManager"),
 connectionSession, databaseConnectionManager);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private void setProcessEngine(final ProcessEngine processEngine) {
+        
Plugins.getMemberAccessor().set(FrontendChannelInboundHandler.class.getDeclaredField("processEngine"),
 frontendChannelInboundHandler, processEngine);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @SneakyThrows(ReflectiveOperationException.class)
+    private Collection<Class<? extends Exception>> getExpectedExceptions() {
+        return (Collection<Class<? extends Exception>>) 
Plugins.getMemberAccessor().get(ExpectedExceptions.class.getDeclaredField("EXCEPTIONS"),
 null);
+    }
 }

Reply via email to