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  }