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));
}
}