@@ -825,3 +825,106 @@ test('parseResponse parses record data', () => {
825825 // Verify value is a Buffer
826826 ok ( Buffer . isBuffer ( record . value ) )
827827} )
828+
829+ test ( 'parseResponse handles truncated records' , ( ) => {
830+ // Create a response with records data
831+ // First create a record batch
832+ const timestamp = BigInt ( Date . now ( ) )
833+ const recordsBatch = Writer . create ( )
834+ // Record batch structure
835+ . appendInt64 ( 0n ) // firstOffset
836+ . appendInt32 ( 60 ) // length - this would be dynamically computed in real usage
837+ . appendInt32 ( 0 ) // partitionLeaderEpoch
838+ . appendInt8 ( 2 ) // magic (record format version)
839+ . appendUnsignedInt32 ( 0 ) // crc - would be computed properly in real code
840+ . appendInt16 ( 0 ) // attributes
841+ . appendInt32 ( 0 ) // lastOffsetDelta
842+ . appendInt64 ( timestamp ) // firstTimestamp
843+ . appendInt64 ( timestamp ) // maxTimestamp
844+ . appendInt64 ( - 1n ) // producerId - not specified
845+ . appendInt16 ( 0 ) // producerEpoch
846+ . appendInt32 ( 0 ) // firstSequence
847+ . appendInt32 ( 1 ) // number of records
848+ // Single record
849+ . appendVarInt ( 8 ) // length of the record
850+ . appendInt8 ( 0 ) // attributes
851+ . appendVarInt64 ( 0n ) // timestampDelta
852+ . appendVarInt ( 0 ) // offsetDelta
853+ . appendVarIntBytes ( null ) // key
854+ . appendVarIntBytes ( Buffer . from ( 'test-value' ) ) // value
855+ . appendVarIntArray ( [ ] , ( ) => { } ) // No headers
856+ // Truncated batch
857+ . appendInt64 ( 0n ) // firstOffset
858+ . appendInt32 ( 60 ) // length
859+
860+ // Now create the full response
861+ const writer = Writer . create ( )
862+ . appendInt32 ( 0 ) // throttleTimeMs
863+ . appendInt16 ( 0 ) // errorCode (success)
864+ . appendInt32 ( 123 ) // sessionId
865+ // Responses array - using tagged fields format
866+ . appendArray (
867+ [
868+ {
869+ topicId : '12345678-1234-1234-1234-123456789abc' ,
870+ partitions : [
871+ {
872+ partitionIndex : 0 ,
873+ errorCode : 0 ,
874+ highWatermark : 100n ,
875+ lastStableOffset : 100n ,
876+ logStartOffset : 0n ,
877+ abortedTransactions : [ ] ,
878+ preferredReadReplica : - 1 ,
879+ recordsBatch
880+ }
881+ ]
882+ }
883+ ] ,
884+ ( w , topic ) => {
885+ w . appendUUID ( topic . topicId )
886+ // Partitions array
887+ . appendArray ( topic . partitions , ( w , partition ) => {
888+ w . appendInt32 ( partition . partitionIndex )
889+ . appendInt16 ( partition . errorCode )
890+ . appendInt64 ( partition . highWatermark )
891+ . appendInt64 ( partition . lastStableOffset )
892+ . appendInt64 ( partition . logStartOffset )
893+ // Aborted transactions array (empty)
894+ . appendArray ( partition . abortedTransactions , ( ) => { } )
895+ . appendInt32 ( partition . preferredReadReplica )
896+
897+ // Add records batch
898+ . appendUnsignedVarInt ( partition . recordsBatch . length + 1 )
899+ . appendFrom ( partition . recordsBatch )
900+ } )
901+ }
902+ )
903+ . appendInt8 ( 0 ) // Root tagged fields
904+
905+ const response = parseResponse ( 1 , 1 , 17 , Reader . from ( writer ) )
906+
907+ // Verify the records were parsed correctly
908+ ok ( response . responses [ 0 ] . partitions [ 0 ] . records , 'Records should be defined' )
909+
910+ const batch = response . responses [ 0 ] . partitions [ 0 ] . records [ 0 ] !
911+ const record = batch . records [ 0 ]
912+
913+ deepStrictEqual (
914+ {
915+ firstOffset : batch . firstOffset ,
916+ recordsLength : batch . records . length ,
917+ offsetDelta : record . offsetDelta ,
918+ valueString : record . value . toString ( )
919+ } ,
920+ {
921+ firstOffset : 0n ,
922+ recordsLength : 1 ,
923+ offsetDelta : 0 ,
924+ valueString : 'test-value'
925+ }
926+ )
927+
928+ // Verify value is a Buffer
929+ ok ( Buffer . isBuffer ( record . value ) )
930+ } )
0 commit comments