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 164ee5d9485 Add more test cases on FirebirdPacketCodecEngineTest 
(#38153)
164ee5d9485 is described below

commit 164ee5d9485aba2674e67e42599b5b3f10c400c0
Author: Liang Zhang <[email protected]>
AuthorDate: Mon Feb 23 11:56:26 2026 +0800

    Add more test cases on FirebirdPacketCodecEngineTest (#38153)
    
    * Add more test cases on FirebirdPacketCodecEngineTest
    
    * Add more test cases on FirebirdPacketCodecEngineTest
---
 .../codec/FirebirdPacketCodecEngineTest.java       | 284 ++++++++++++---------
 1 file changed, 157 insertions(+), 127 deletions(-)

diff --git 
a/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/codec/FirebirdPacketCodecEngineTest.java
 
b/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/codec/FirebirdPacketCodecEngineTest.java
index daa5afadbe9..7c0f1331f5f 100644
--- 
a/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/codec/FirebirdPacketCodecEngineTest.java
+++ 
b/database/protocol/dialect/firebird/src/test/java/org/apache/shardingsphere/database/protocol/firebird/codec/FirebirdPacketCodecEngineTest.java
@@ -18,9 +18,10 @@
 package org.apache.shardingsphere.database.protocol.firebird.codec;
 
 import io.netty.buffer.ByteBuf;
-import io.netty.buffer.CompositeByteBuf;
+import io.netty.buffer.Unpooled;
 import io.netty.channel.ChannelHandlerContext;
-import io.netty.util.AttributeKey;
+import lombok.SneakyThrows;
+import org.apache.shardingsphere.database.protocol.constant.CommonConstants;
 import 
org.apache.shardingsphere.database.protocol.firebird.constant.FirebirdConstant;
 import 
org.apache.shardingsphere.database.protocol.firebird.constant.protocol.FirebirdProtocolVersion;
 import 
org.apache.shardingsphere.database.protocol.firebird.packet.command.FirebirdCommandPacketFactory;
@@ -30,21 +31,26 @@ import 
org.apache.shardingsphere.database.protocol.packet.DatabasePacket;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockedStatic;
+import org.mockito.internal.configuration.plugins.Plugins;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.junit.jupiter.MockitoSettings;
 import org.mockito.quality.Strictness;
 
-import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Stream;
 
-import static org.hamcrest.Matchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -58,175 +64,199 @@ import static org.mockito.Mockito.when;
 @MockitoSettings(strictness = Strictness.LENIENT)
 class FirebirdPacketCodecEngineTest {
     
+    private final FirebirdPacketCodecEngine codecEngine = new 
FirebirdPacketCodecEngine();
+    
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private ChannelHandlerContext context;
     
-    @Mock
-    private ByteBuf byteBuf;
-    
-    @Mock
-    private DatabasePacket packet;
-    
     @BeforeEach
-    void setup() {
-        
when(context.channel().attr(AttributeKey.<Charset>valueOf(Charset.class.getName())).get()).thenReturn(StandardCharsets.UTF_8);
+    void setUp() {
+        
when(context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY).get()).thenReturn(StandardCharsets.UTF_8);
         
when(context.channel().attr(FirebirdConstant.CONNECTION_PROTOCOL_VERSION).get()).thenReturn(FirebirdProtocolVersion.PROTOCOL_VERSION10);
-        when(context.alloc().compositeBuffer(anyInt())).thenAnswer(inv -> 
mock(CompositeByteBuf.class, org.mockito.Mockito.RETURNS_SELF));
+        when(context.alloc().compositeBuffer(anyInt())).thenAnswer(invocation 
-> Unpooled.compositeBuffer(invocation.getArgument(0)));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("validHeaderCases")
+    void assertIsValidHeader(final String name, final int readableBytes, final 
boolean expectedValid) {
+        assertThat(codecEngine.isValidHeader(readableBytes), 
is(expectedValid));
+    }
+    
+    @ParameterizedTest(name = "{0}")
+    @MethodSource("fixedLengthCommandCases")
+    void assertDecodeFixedLengthCommand(final String name, final 
FirebirdCommandPacketType commandType, final int packetLength, final int 
packetCount) {
+        ByteBuf in = createCommandPackets(commandType, packetLength, 
packetCount);
+        List<Object> out = new LinkedList<>();
+        codecEngine.decode(context, in, out);
+        assertThat(out.size(), is(packetCount));
+        assertThat(((ByteBuf) out.get(0)).readableBytes(), is(packetLength));
     }
     
     @Test
-    void assertIsValidHeader() {
-        assertTrue(new FirebirdPacketCodecEngine().isValidHeader(50));
+    void assertDecodeWithIncompleteHeader() {
+        final ByteBuf pendingMessage = Unpooled.wrappedBuffer(new byte[]{1, 
2});
+        getPendingMessages().add(pendingMessage);
+        ByteBuf in = Unpooled.wrappedBuffer(new byte[]{3});
+        List<Object> out = new LinkedList<>();
+        assertThat(in.capacity(), is(1));
+        codecEngine.decode(context, in, out);
+        assertTrue(out.isEmpty());
+        assertThat(getPendingMessages().size(), is(1));
+        assertThat(getPendingMessages().get(0).readableBytes(), is(3));
     }
     
     @Test
-    void assertIsInvalidHeader() {
-        assertFalse(new FirebirdPacketCodecEngine().isValidHeader(3));
+    void assertDecodeWithVoidCommandType() {
+        ByteBuf in = createCommandPacket(FirebirdCommandPacketType.VOID, 4);
+        List<Object> out = new LinkedList<>();
+        assertThat(in.readerIndex(), is(0));
+        codecEngine.decode(context, in, out);
+        assertTrue(out.isEmpty());
+        assertTrue(getPendingMessages().isEmpty());
     }
     
     @Test
-    void assertDecodeSingleAllocateStatement() {
-        ByteBuf in = mock(ByteBuf.class);
-        ByteBuf slice = mock(ByteBuf.class);
-        when(in.readableBytes()).thenReturn(0);
-        when(in.readerIndex()).thenReturn(0);
-        
when(in.getInt(0)).thenReturn(FirebirdCommandPacketType.ALLOCATE_STATEMENT.getValue());
-        when(in.readRetainedSlice(8)).thenReturn(slice);
-        when(slice.readableBytes()).thenReturn(8);
+    void assertDecodeWithExpectedLength() {
+        ByteBuf in = 
createCommandPacket(FirebirdCommandPacketType.PREPARE_STATEMENT, 8);
         List<Object> out = new LinkedList<>();
-        new FirebirdPacketCodecEngine().decode(context, in, out);
+        assertThat(in.writerIndex(), is(8));
+        try (MockedStatic<FirebirdCommandPacketFactory> ignored = 
mockExpectedLength(8)) {
+            codecEngine.decode(context, in, out);
+        }
         assertThat(out.size(), is(1));
         assertThat(((ByteBuf) out.get(0)).readableBytes(), is(8));
+        assertNull(getPendingPacketType());
     }
     
     @Test
-    void assertDecodeMultiplePackets() {
-        ByteBuf in = mock(ByteBuf.class);
-        ByteBuf slice1 = mock(ByteBuf.class);
-        ByteBuf slice2 = mock(ByteBuf.class);
-        when(in.readableBytes()).thenReturn(8, 0);
-        when(in.readerIndex()).thenReturn(0);
-        
when(in.getInt(0)).thenReturn(FirebirdCommandPacketType.ALLOCATE_STATEMENT.getValue());
-        when(in.readRetainedSlice(8)).thenReturn(slice1, slice2);
+    void assertDecodeWithNonPositiveExpectedLength() {
+        ByteBuf in = 
createCommandPacket(FirebirdCommandPacketType.PREPARE_STATEMENT, 8);
         List<Object> out = new LinkedList<>();
-        new FirebirdPacketCodecEngine().decode(context, in, out);
-        assertThat(out.size(), is(2));
+        assertTrue(in.maxCapacity() >= 8);
+        try (MockedStatic<FirebirdCommandPacketFactory> ignored = 
mockExpectedLength(0)) {
+            codecEngine.decode(context, in, out);
+        }
+        assertThat(out.size(), is(1));
+        assertThat(((ByteBuf) out.get(0)).readableBytes(), is(8));
     }
     
     @Test
-    void assertDecodeWithPartialPacket() {
-        ByteBuf in = mock(ByteBuf.class);
-        ByteBuf slice = mock(ByteBuf.class);
-        ByteBuf payloadSlice = mock(ByteBuf.class);
-        when(in.readableBytes()).thenReturn(8, 8, 8);
-        when(in.readerIndex()).thenReturn(0);
-        
when(in.getInt(0)).thenReturn(FirebirdCommandPacketType.INFO_REQUEST.getValue());
-        when(in.writerIndex()).thenReturn(8);
-        when(in.capacity()).thenReturn(16);
-        when(in.isReadable()).thenReturn(true, false);
-        when(in.retainedSlice(anyInt(), anyInt())).thenReturn(payloadSlice);
-        when(payloadSlice.release()).thenReturn(true);
-        when(in.readRetainedSlice(8)).thenReturn(slice);
+    void assertDecodeWithExpectedLengthOverflow() {
+        ByteBuf in = 
createCommandPacket(FirebirdCommandPacketType.PREPARE_STATEMENT, 8);
         List<Object> out = new LinkedList<>();
-        new FirebirdPacketCodecEngine().decode(context, in, out);
-        assertThat(out.size(), is(1));
+        assertThat(in.refCnt(), is(1));
+        try (MockedStatic<FirebirdCommandPacketFactory> ignored = 
mockExpectedLength(12)) {
+            codecEngine.decode(context, in, out);
+        }
+        assertTrue(out.isEmpty());
+        assertThat(getPendingPacketType(), 
is(FirebirdCommandPacketType.PREPARE_STATEMENT));
+        assertThat(getPendingMessages().size(), is(1));
+        assertThat(getPendingMessages().get(0).readableBytes(), is(8));
     }
     
     @Test
-    void assertDecodeWithTruncatedPacketAcrossBuffers() {
-        ByteBuf firstPart = mock(ByteBuf.class);
-        ByteBuf firstSlice = mock(ByteBuf.class);
-        ByteBuf secondPart = mock(ByteBuf.class);
-        ByteBuf secondSlice = mock(ByteBuf.class);
-        CompositeByteBuf firstComposite = mock(CompositeByteBuf.class, 
org.mockito.Mockito.RETURNS_SELF);
-        CompositeByteBuf secondComposite = mock(CompositeByteBuf.class, 
org.mockito.Mockito.RETURNS_SELF);
-        
when(context.alloc().compositeBuffer(anyInt())).thenReturn(firstComposite, 
secondComposite);
-        ByteBuf firstPayloadSlice = mock(ByteBuf.class);
-        ByteBuf compositePayloadSlice = mock(ByteBuf.class);
-        ByteBuf compositeOutputSlice = mock(ByteBuf.class);
-        when(firstPart.readableBytes()).thenReturn(8, 8, 8, 8);
-        when(firstPart.readerIndex()).thenReturn(0);
-        
when(firstPart.getInt(0)).thenReturn(FirebirdCommandPacketType.PREPARE_STATEMENT.getValue());
-        when(firstPart.writerIndex()).thenReturn(8);
-        when(firstPart.capacity()).thenReturn(8);
-        when(firstPart.isReadable()).thenReturn(true, true, false);
-        when(firstPart.retainedSlice(anyInt(), 
anyInt())).thenReturn(firstPayloadSlice);
-        when(firstPayloadSlice.release()).thenReturn(true);
-        when(firstPart.readRetainedSlice(8)).thenReturn(firstSlice);
-        when(secondPart.readableBytes()).thenReturn(4, 0);
-        when(secondPart.isReadable()).thenReturn(true, false);
-        when(secondPart.writerIndex()).thenReturn(4);
-        when(secondPart.capacity()).thenReturn(4);
-        when(secondPart.readRetainedSlice(4)).thenReturn(secondSlice);
-        when(firstComposite.isReadable()).thenReturn(true, false);
-        when(firstComposite.readableBytes()).thenReturn(12, 12, 12);
-        when(firstComposite.readerIndex()).thenReturn(0);
-        
when(firstComposite.getInt(0)).thenReturn(FirebirdCommandPacketType.PREPARE_STATEMENT.getValue());
-        when(firstComposite.retainedSlice(anyInt(), 
anyInt())).thenReturn(compositePayloadSlice);
-        when(compositePayloadSlice.release()).thenReturn(true);
-        
when(firstComposite.readRetainedSlice(12)).thenReturn(compositeOutputSlice);
-        when(compositeOutputSlice.readableBytes()).thenReturn(12);
-        when(firstComposite.release()).thenReturn(true);
+    void assertDecodeWithExpectedLengthException() {
+        ByteBuf in = 
createCommandPacket(FirebirdCommandPacketType.PREPARE_STATEMENT, 8);
         List<Object> out = new LinkedList<>();
-        FirebirdPacketCodecEngine codecEngine = new 
FirebirdPacketCodecEngine();
-        try (MockedStatic<FirebirdCommandPacketFactory> mocked = 
mockStatic(FirebirdCommandPacketFactory.class)) {
-            mocked.when(() -> 
FirebirdCommandPacketFactory.getExpectedLength(any(), any(), 
any())).thenReturn(12, 12);
-            codecEngine.decode(context, firstPart, out);
-            assertTrue(out.isEmpty());
-            codecEngine.decode(context, secondPart, out);
-            assertThat(out.size(), is(1));
-            assertThat(((ByteBuf) out.get(0)).readableBytes(), is(12));
+        assertThat(in.readableBytes(), is(8));
+        try (MockedStatic<FirebirdCommandPacketFactory> ignored = 
mockExpectedLengthException()) {
+            codecEngine.decode(context, in, out);
         }
+        assertTrue(out.isEmpty());
+        assertThat(getPendingPacketType(), 
is(FirebirdCommandPacketType.PREPARE_STATEMENT));
+        assertThat(getPendingMessages().size(), is(1));
     }
     
     @Test
-    void assertDecodeWithFullBufferAndValidLength() {
-        ByteBuf in = mock(ByteBuf.class);
-        ByteBuf slice = mock(ByteBuf.class);
-        CompositeByteBuf composite = mock(CompositeByteBuf.class, 
org.mockito.Mockito.RETURNS_SELF);
-        when(context.alloc().compositeBuffer(anyInt())).thenReturn(composite);
-        ByteBuf payloadSlice = mock(ByteBuf.class);
-        when(in.readableBytes()).thenReturn(8, 8, 8, 8);
-        when(in.readerIndex()).thenReturn(0);
-        
when(in.getInt(0)).thenReturn(FirebirdCommandPacketType.PREPARE_STATEMENT.getValue());
-        when(in.writerIndex()).thenReturn(8);
-        when(in.capacity()).thenReturn(8);
-        when(in.isReadable()).thenReturn(true, false);
-        when(in.retainedSlice(anyInt(), anyInt())).thenReturn(payloadSlice);
-        when(payloadSlice.release()).thenReturn(true);
-        when(in.readRetainedSlice(8)).thenReturn(slice);
-        when(composite.isReadable()).thenReturn(true, false);
-        when(composite.readableBytes()).thenReturn(8, 8, 8);
-        when(composite.readerIndex()).thenReturn(0);
-        
when(composite.getInt(0)).thenReturn(FirebirdCommandPacketType.PREPARE_STATEMENT.getValue());
-        when(composite.retainedSlice(anyInt(), 
anyInt())).thenReturn(payloadSlice);
-        when(slice.readableBytes()).thenReturn(8);
-        when(composite.readRetainedSlice(8)).thenReturn(slice);
-        when(composite.release()).thenReturn(true);
+    void assertDecodeWithProcessPacketsExceptionAndNoPendingMessages() {
+        
when(context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY).get()).thenThrow(IllegalStateException.class);
+        ByteBuf in = 
createCommandPacket(FirebirdCommandPacketType.INFO_REQUEST, 8);
         List<Object> out = new LinkedList<>();
-        try (MockedStatic<FirebirdCommandPacketFactory> mocked = 
mockStatic(FirebirdCommandPacketFactory.class)) {
-            mocked.when(() -> 
FirebirdCommandPacketFactory.getExpectedLength(any(), any(), 
any())).thenReturn(8);
-            new FirebirdPacketCodecEngine().decode(context, in, out);
-            assertThat(out.size(), is(1));
-            assertThat(((ByteBuf) out.get(0)).readableBytes(), is(8));
-        }
+        assertThrows(IllegalStateException.class, () -> 
codecEngine.decode(context, in, out));
+    }
+    
+    @Test
+    void assertDecodeWithProcessPacketsExceptionAndPendingMessages() {
+        
when(context.channel().attr(CommonConstants.CHARSET_ATTRIBUTE_KEY).get()).thenThrow(IllegalStateException.class);
+        final ByteBuf pendingMessage = Unpooled.wrappedBuffer(new byte[]{1, 2, 
3, 4});
+        getPendingMessages().add(pendingMessage);
+        ByteBuf in = 
createCommandPacket(FirebirdCommandPacketType.INFO_REQUEST, 8);
+        List<Object> out = new LinkedList<>();
+        assertThrows(IllegalStateException.class, () -> 
codecEngine.decode(context, in, out));
     }
     
     @Test
     void assertEncode() {
-        new FirebirdPacketCodecEngine().encode(context, packet, byteBuf);
+        DatabasePacket packet = mock(DatabasePacket.class);
+        ByteBuf byteBuf = mock(ByteBuf.class);
+        codecEngine.encode(context, packet, byteBuf);
         verify(packet).write(any(FirebirdPacketPayload.class));
     }
     
     @Test
-    void assertEncodeOccursException() {
+    void assertEncodeWithException() {
+        DatabasePacket packet = mock(DatabasePacket.class);
+        ByteBuf byteBuf = mock(ByteBuf.class);
         
doThrow(RuntimeException.class).when(packet).write(any(FirebirdPacketPayload.class));
-        new FirebirdPacketCodecEngine().encode(context, packet, byteBuf);
+        codecEngine.encode(context, packet, byteBuf);
         verify(byteBuf).resetWriterIndex();
     }
     
     @Test
     void assertCreatePacketPayload() {
-        assertThat(new 
FirebirdPacketCodecEngine().createPacketPayload(byteBuf, 
StandardCharsets.UTF_8).getByteBuf(), is(byteBuf));
+        ByteBuf byteBuf = mock(ByteBuf.class);
+        assertThat(codecEngine.createPacketPayload(byteBuf, 
StandardCharsets.UTF_8).getByteBuf(), is(byteBuf));
+    }
+    
+    private ByteBuf createCommandPackets(final FirebirdCommandPacketType 
commandType, final int packetLength, final int packetCount) {
+        ByteBuf result = Unpooled.buffer(packetLength * packetCount);
+        for (int i = 0; i < packetCount; i++) {
+            result.writeBytes(createCommandPacket(commandType, packetLength));
+        }
+        return result;
+    }
+    
+    private ByteBuf createCommandPacket(final FirebirdCommandPacketType 
commandType, final int packetLength) {
+        ByteBuf result = Unpooled.buffer(packetLength);
+        result.writeInt(commandType.getValue());
+        result.writeZero(packetLength - Integer.BYTES);
+        return result;
+    }
+    
+    private MockedStatic<FirebirdCommandPacketFactory> 
mockExpectedLength(final int expectedLength) {
+        MockedStatic<FirebirdCommandPacketFactory> result = 
mockStatic(FirebirdCommandPacketFactory.class);
+        result.when(() -> 
FirebirdCommandPacketFactory.getExpectedLength(any(), any(), 
any())).thenReturn(expectedLength);
+        return result;
+    }
+    
+    private MockedStatic<FirebirdCommandPacketFactory> 
mockExpectedLengthException() {
+        MockedStatic<FirebirdCommandPacketFactory> result = 
mockStatic(FirebirdCommandPacketFactory.class);
+        result.when(() -> 
FirebirdCommandPacketFactory.getExpectedLength(any(), any(), 
any())).thenThrow(IndexOutOfBoundsException.class);
+        return result;
+    }
+    
+    @SuppressWarnings("unchecked")
+    @SneakyThrows(ReflectiveOperationException.class)
+    private List<ByteBuf> getPendingMessages() {
+        return (List<ByteBuf>) 
Plugins.getMemberAccessor().get(FirebirdPacketCodecEngine.class.getDeclaredField("pendingMessages"),
 codecEngine);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private FirebirdCommandPacketType getPendingPacketType() {
+        return (FirebirdCommandPacketType) 
Plugins.getMemberAccessor().get(FirebirdPacketCodecEngine.class.getDeclaredField("pendingPacketType"),
 codecEngine);
+    }
+    
+    private static Stream<Arguments> validHeaderCases() {
+        return Stream.of(
+                Arguments.of("readable bytes greater than header", 5, true),
+                Arguments.of("readable bytes equal to header", 4, true),
+                Arguments.of("readable bytes less than header", 3, false));
+    }
+    
+    private static Stream<Arguments> fixedLengthCommandCases() {
+        return Stream.of(
+                Arguments.of("decode allocate statement", 
FirebirdCommandPacketType.ALLOCATE_STATEMENT, 8, 1),
+                Arguments.of("decode free statement", 
FirebirdCommandPacketType.FREE_STATEMENT, 12, 1),
+                Arguments.of("decode consecutive free statements", 
FirebirdCommandPacketType.FREE_STATEMENT, 12, 2));
     }
 }

Reply via email to