github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/topic/topicreaderinternal/batch_test.go (about) 1 package topicreaderinternal 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/stretchr/testify/require" 8 ) 9 10 func TestBatch_New(t *testing.T) { 11 t.Run("OK", func(t *testing.T) { 12 session := &partitionSession{} 13 m1 := &PublicMessage{ 14 commitRange: commitRange{commitOffsetStart: 1, commitOffsetEnd: 2, partitionSession: session}, 15 } 16 m2 := &PublicMessage{ 17 commitRange: commitRange{commitOffsetStart: 2, commitOffsetEnd: 3, partitionSession: session}, 18 } 19 batch, err := newBatch(session, []*PublicMessage{m1, m2}) 20 require.NoError(t, err) 21 22 expected := &PublicBatch{ 23 Messages: []*PublicMessage{m1, m2}, 24 commitRange: commitRange{commitOffsetStart: 1, commitOffsetEnd: 3, partitionSession: session}, 25 } 26 require.Equal(t, expected, batch) 27 }) 28 } 29 30 func TestBatch_Cut(t *testing.T) { 31 t.Run("Full", func(t *testing.T) { 32 session := &partitionSession{} 33 batch, _ := newBatch(session, []*PublicMessage{{WrittenAt: testTime(1)}, {WrittenAt: testTime(2)}}) 34 35 head, rest := batch.cutMessages(100) 36 37 require.Equal(t, batch, head) 38 require.True(t, rest.isEmpty()) 39 }) 40 t.Run("Zero", func(t *testing.T) { 41 session := &partitionSession{} 42 batch, _ := newBatch(session, []*PublicMessage{{WrittenAt: testTime(1)}, {WrittenAt: testTime(2)}}) 43 44 head, rest := batch.cutMessages(0) 45 46 require.Equal(t, batch, rest) 47 require.True(t, head.isEmpty()) 48 }) 49 t.Run("Middle", func(t *testing.T) { 50 session := &partitionSession{} 51 batch, _ := newBatch(session, []*PublicMessage{{WrittenAt: testTime(1)}, {WrittenAt: testTime(2)}}) 52 53 head, rest := batch.cutMessages(1) 54 55 expectedBatchHead, _ := newBatch(session, []*PublicMessage{{WrittenAt: testTime(1)}}) 56 expectedBatchRest, _ := newBatch(session, []*PublicMessage{{WrittenAt: testTime(2)}}) 57 require.Equal(t, expectedBatchHead, head) 58 require.Equal(t, expectedBatchRest, rest) 59 }) 60 } 61 62 func TestBatch_Extend(t *testing.T) { 63 t.Run("Ok", func(t *testing.T) { 64 session := &partitionSession{} 65 m1 := &PublicMessage{ 66 WrittenAt: time.Date(2022, 6, 17, 15, 15, 0, 1, time.UTC), 67 commitRange: commitRange{commitOffsetStart: 10, commitOffsetEnd: 11, partitionSession: session}, 68 } 69 m2 := &PublicMessage{ 70 WrittenAt: time.Date(2022, 6, 17, 15, 15, 0, 2, time.UTC), 71 commitRange: commitRange{commitOffsetStart: 11, commitOffsetEnd: 12, partitionSession: session}, 72 } 73 74 b1 := &PublicBatch{ 75 Messages: []*PublicMessage{m1}, 76 commitRange: m1.commitRange, 77 } 78 79 b2 := &PublicBatch{ 80 Messages: []*PublicMessage{m2}, 81 commitRange: m2.commitRange, 82 } 83 res, err := b1.append(b2) 84 require.NoError(t, err) 85 86 expected := &PublicBatch{ 87 Messages: []*PublicMessage{m1, m2}, 88 commitRange: commitRange{commitOffsetStart: 10, commitOffsetEnd: 12, partitionSession: session}, 89 } 90 require.Equal(t, expected, res) 91 }) 92 t.Run("BadInterval", func(t *testing.T) { 93 m1 := &PublicMessage{ 94 WrittenAt: time.Date(2022, 6, 17, 15, 15, 0, 1, time.UTC), 95 commitRange: commitRange{commitOffsetStart: 10, commitOffsetEnd: 11}, 96 } 97 m2 := &PublicMessage{ 98 WrittenAt: time.Date(2022, 6, 17, 15, 15, 0, 2, time.UTC), 99 commitRange: commitRange{commitOffsetStart: 20, commitOffsetEnd: 30}, 100 } 101 102 b1 := &PublicBatch{ 103 Messages: []*PublicMessage{m1}, 104 commitRange: m1.commitRange, 105 } 106 107 b2 := &PublicBatch{ 108 Messages: []*PublicMessage{m2}, 109 commitRange: m2.commitRange, 110 } 111 res, err := b1.append(b2) 112 require.Error(t, err) 113 114 require.Nil(t, res) 115 }) 116 t.Run("BadSession", func(t *testing.T) { 117 session1 := &partitionSession{} 118 session2 := &partitionSession{} 119 120 m1 := &PublicMessage{ 121 WrittenAt: time.Date(2022, 6, 17, 15, 15, 0, 1, time.UTC), 122 commitRange: commitRange{commitOffsetStart: 10, commitOffsetEnd: 11, partitionSession: session1}, 123 } 124 m2 := &PublicMessage{ 125 WrittenAt: time.Date(2022, 6, 17, 15, 15, 0, 2, time.UTC), 126 commitRange: commitRange{commitOffsetStart: 11, commitOffsetEnd: 12, partitionSession: session2}, 127 } 128 129 b1 := &PublicBatch{ 130 Messages: []*PublicMessage{m1}, 131 commitRange: m1.commitRange, 132 } 133 134 b2 := &PublicBatch{ 135 Messages: []*PublicMessage{m2}, 136 commitRange: m2.commitRange, 137 } 138 res, err := b1.append(b2) 139 require.Error(t, err) 140 require.Nil(t, res) 141 }) 142 } 143 144 func TestSplitBytesByBatches(t *testing.T) { 145 checkTotalBytes := func(t *testing.T, totalBytes int, batches ...*PublicBatch) { 146 sum := 0 147 for _, batch := range batches { 148 for _, msg := range batch.Messages { 149 sum += msg.bufferBytesAccount 150 } 151 } 152 153 require.Equal(t, totalBytes, sum) 154 } 155 156 t.Run("Empty", func(t *testing.T) { 157 require.NoError(t, splitBytesByMessagesInBatches(nil, 0)) 158 }) 159 t.Run("BytesToNoMessages", func(t *testing.T) { 160 require.Error(t, splitBytesByMessagesInBatches(nil, 10)) 161 }) 162 t.Run("MetadataOnlyEqually", func(t *testing.T) { 163 totalBytes := 30 164 batch, err := newBatch(nil, []*PublicMessage{{}, {}, {}}) 165 require.NoError(t, err) 166 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch}, totalBytes)) 167 168 for _, msg := range batch.Messages { 169 require.Equal(t, 10, msg.bufferBytesAccount) 170 } 171 checkTotalBytes(t, totalBytes, batch) 172 }) 173 t.Run("MetadataOnlyWithReminder", func(t *testing.T) { 174 totalBytes := 5 175 batch, err := newBatch(nil, []*PublicMessage{{}, {}, {}}) 176 require.NoError(t, err) 177 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch}, 5)) 178 179 require.Equal(t, 2, batch.Messages[0].bufferBytesAccount) 180 require.Equal(t, 2, batch.Messages[1].bufferBytesAccount) 181 require.Equal(t, 1, batch.Messages[2].bufferBytesAccount) 182 checkTotalBytes(t, totalBytes, batch) 183 }) 184 t.Run("OnlyData", func(t *testing.T) { 185 totalBytes := 30 186 batch, err := newBatch(nil, []*PublicMessage{{}, {}, {}}) 187 require.NoError(t, err) 188 for i := range batch.Messages { 189 batch.Messages[i].rawDataLen = 10 190 } 191 192 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch}, totalBytes)) 193 require.Equal(t, 10, batch.Messages[0].bufferBytesAccount) 194 require.Equal(t, 10, batch.Messages[1].bufferBytesAccount) 195 require.Equal(t, 10, batch.Messages[2].bufferBytesAccount) 196 checkTotalBytes(t, totalBytes, batch) 197 }) 198 t.Run("DataAndMetadataEqually", func(t *testing.T) { 199 totalBytes := 30 200 batch, err := newBatch(nil, []*PublicMessage{{}, {}, {}}) 201 require.NoError(t, err) 202 for i := range batch.Messages { 203 batch.Messages[i].rawDataLen = 5 204 } 205 206 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch}, totalBytes)) 207 require.Equal(t, 10, batch.Messages[0].bufferBytesAccount) 208 require.Equal(t, 10, batch.Messages[1].bufferBytesAccount) 209 require.Equal(t, 10, batch.Messages[2].bufferBytesAccount) 210 checkTotalBytes(t, totalBytes, batch) 211 }) 212 t.Run("DataAndMetadataEquallyTwoBatches", func(t *testing.T) { 213 totalBytes := 30 214 batch1, err := newBatch(nil, []*PublicMessage{{}, {}}) 215 require.NoError(t, err) 216 batch1.Messages[0].rawDataLen = 5 217 batch1.Messages[1].rawDataLen = 5 218 batch2, err := newBatch(nil, []*PublicMessage{{}}) 219 require.NoError(t, err) 220 batch2.Messages[0].rawDataLen = 5 221 222 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch1, batch2}, totalBytes)) 223 require.Equal(t, 10, batch1.Messages[0].bufferBytesAccount) 224 require.Equal(t, 10, batch1.Messages[1].bufferBytesAccount) 225 require.Equal(t, 10, batch2.Messages[0].bufferBytesAccount) 226 checkTotalBytes(t, totalBytes, batch1, batch2) 227 }) 228 t.Run("DataAndMetadataWithReminder", func(t *testing.T) { 229 totalBytes := 32 230 batch, err := newBatch(nil, []*PublicMessage{{}, {}, {}}) 231 require.NoError(t, err) 232 for i := range batch.Messages { 233 batch.Messages[i].rawDataLen = 5 234 } 235 236 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch}, totalBytes)) 237 require.Equal(t, 11, batch.Messages[0].bufferBytesAccount) 238 require.Equal(t, 11, batch.Messages[1].bufferBytesAccount) 239 require.Equal(t, 10, batch.Messages[2].bufferBytesAccount) 240 checkTotalBytes(t, totalBytes, batch) 241 }) 242 t.Run("BytesSmallerThenCalcedData", func(t *testing.T) { 243 totalBytes := 2 244 245 batch, err := newBatch(nil, []*PublicMessage{{}, {}, {}}) 246 require.NoError(t, err) 247 for i := range batch.Messages { 248 batch.Messages[i].rawDataLen = 5 249 } 250 251 require.NoError(t, splitBytesByMessagesInBatches([]*PublicBatch{batch}, totalBytes)) 252 253 summ := 0 254 for _, msg := range batch.Messages { 255 summ += msg.bufferBytesAccount 256 } 257 checkTotalBytes(t, totalBytes, batch) 258 }) 259 } 260 261 func testTime(num int) time.Time { 262 return time.Date(2022, 6, 17, 0, 0, 0, num, time.UTC) 263 }