github.com/klaytn/klaytn@v1.10.2/datasync/chaindatafetcher/kafka/consumer_test.go (about)

     1  // Copyright 2020 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package kafka
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"math/rand"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/klaytn/klaytn/datasync/chaindatafetcher/kafka/mocks"
    30  
    31  	"github.com/Shopify/sarama"
    32  	"github.com/klaytn/klaytn/common"
    33  	"github.com/stretchr/testify/assert"
    34  )
    35  
    36  func Test_newSegment_Success_LegacyMessage(t *testing.T) {
    37  	value := common.MakeRandomBytes(100)
    38  	rand.Seed(time.Now().UnixNano())
    39  	total := uint64(10)
    40  	idx := rand.Uint64() % total
    41  	totalBytes := common.Int64ToByteBigEndian(total)
    42  	idxBytes := common.Int64ToByteBigEndian(idx)
    43  	key := "test-key"
    44  	msg := &sarama.ConsumerMessage{
    45  		Headers: []*sarama.RecordHeader{
    46  			{Key: []byte(KeyTotalSegments), Value: totalBytes},
    47  			{Key: []byte(KeySegmentIdx), Value: idxBytes},
    48  		},
    49  		Key:   []byte(key),
    50  		Value: value,
    51  	}
    52  
    53  	segment, err := newSegment(msg)
    54  	assert.NoError(t, err)
    55  	assert.Equal(t, msg, segment.orig)
    56  	assert.Equal(t, value, segment.value)
    57  	assert.Equal(t, total, segment.total)
    58  	assert.Equal(t, idx, segment.index)
    59  	assert.Equal(t, key, segment.key)
    60  }
    61  
    62  func Test_newSegment_Success_Version1Message(t *testing.T) {
    63  	value := common.MakeRandomBytes(100)
    64  	rand.Seed(time.Now().UnixNano())
    65  	total := uint64(10)
    66  	idx := rand.Uint64() % total
    67  	totalBytes := common.Int64ToByteBigEndian(total)
    68  	idxBytes := common.Int64ToByteBigEndian(idx)
    69  	key := "test-key"
    70  	version := MsgVersion1_0
    71  	versionBytes := []byte(version)
    72  	producerId := GetDefaultProducerId()
    73  	producerIdBytes := []byte(producerId)
    74  
    75  	msg := &sarama.ConsumerMessage{
    76  		Headers: []*sarama.RecordHeader{
    77  			{Key: []byte(KeyTotalSegments), Value: totalBytes},
    78  			{Key: []byte(KeySegmentIdx), Value: idxBytes},
    79  			{Key: []byte(KeyVersion), Value: versionBytes},
    80  			{Key: []byte(KeyProducerId), Value: producerIdBytes},
    81  		},
    82  		Key:   []byte(key),
    83  		Value: value,
    84  	}
    85  
    86  	segment, err := newSegment(msg)
    87  	assert.NoError(t, err)
    88  	assert.Equal(t, msg, segment.orig)
    89  	assert.Equal(t, value, segment.value)
    90  	assert.Equal(t, total, segment.total)
    91  	assert.Equal(t, idx, segment.index)
    92  	assert.Equal(t, key, segment.key)
    93  	assert.Equal(t, version, segment.version)
    94  	assert.Equal(t, producerId, segment.producerId)
    95  }
    96  
    97  func Test_newSegment_Fail(t *testing.T) {
    98  	type testcase struct {
    99  		name   string
   100  		input  *sarama.ConsumerMessage
   101  		errMsg string
   102  	}
   103  
   104  	testcases := []testcase{
   105  		{
   106  			"nil consumer message",
   107  			nil,
   108  			nilConsumerMessageErrorMsg,
   109  		},
   110  		{
   111  			"empty consumer message",
   112  			&sarama.ConsumerMessage{},
   113  			wrongHeaderNumberErrorMsg,
   114  		},
   115  		{
   116  			"wrong first key with legacy header",
   117  			&sarama.ConsumerMessage{
   118  				Headers: []*sarama.RecordHeader{
   119  					{Key: []byte("wrong-header-key")},
   120  					{Key: []byte(KeyTotalSegments)},
   121  				},
   122  			},
   123  			wrongHeaderKeyErrorMsg,
   124  		},
   125  		{
   126  			"wrong second key with legacy header",
   127  			&sarama.ConsumerMessage{
   128  				Headers: []*sarama.RecordHeader{
   129  					{Key: []byte(KeySegmentIdx)},
   130  					{Key: []byte("wrong-header-key")},
   131  				},
   132  			},
   133  			wrongHeaderKeyErrorMsg,
   134  		},
   135  		{
   136  			"wrong first key with 1.0 header",
   137  			&sarama.ConsumerMessage{
   138  				Headers: []*sarama.RecordHeader{
   139  					{Key: []byte("wrong-header-key")},
   140  					{Key: []byte(KeyTotalSegments)},
   141  					{Key: []byte(KeyVersion), Value: []byte(MsgVersion1_0)},
   142  					{Key: []byte(KeyProducerId)},
   143  				},
   144  			},
   145  			wrongHeaderKeyErrorMsg,
   146  		},
   147  		{
   148  			"wrong second key with 1.0 header",
   149  			&sarama.ConsumerMessage{
   150  				Headers: []*sarama.RecordHeader{
   151  					{Key: []byte(KeySegmentIdx)},
   152  					{Key: []byte("wrong-header-key")},
   153  					{Key: []byte(KeyVersion), Value: []byte(MsgVersion1_0)},
   154  					{Key: []byte(KeyProducerId)},
   155  				},
   156  			},
   157  			wrongHeaderKeyErrorMsg,
   158  		},
   159  		{
   160  			"wrong third key with 1.0 header",
   161  			&sarama.ConsumerMessage{
   162  				Headers: []*sarama.RecordHeader{
   163  					{Key: []byte(KeySegmentIdx)},
   164  					{Key: []byte(KeyTotalSegments)},
   165  					{Key: []byte("wrong-header-key")},
   166  					{Key: []byte(KeyProducerId)},
   167  				},
   168  			},
   169  			wrongHeaderKeyErrorMsg,
   170  		},
   171  		{
   172  			"wrong fourth key with 1.0 header",
   173  			&sarama.ConsumerMessage{
   174  				Headers: []*sarama.RecordHeader{
   175  					{Key: []byte(KeySegmentIdx)},
   176  					{Key: []byte(KeyTotalSegments)},
   177  					{Key: []byte(KeyVersion), Value: []byte(MsgVersion1_0)},
   178  					{Key: []byte("wrong-header-key")},
   179  				},
   180  			},
   181  			wrongHeaderKeyErrorMsg,
   182  		},
   183  		{
   184  			"wrong version with 1.0 header",
   185  			&sarama.ConsumerMessage{
   186  				Headers: []*sarama.RecordHeader{
   187  					{Key: []byte(KeySegmentIdx)},
   188  					{Key: []byte(KeyTotalSegments)},
   189  					{Key: []byte(KeyVersion), Value: []byte("wrong-version")},
   190  					{Key: []byte(KeyProducerId)},
   191  				},
   192  			},
   193  			wrongMsgVersionErrorMsg,
   194  		},
   195  	}
   196  
   197  	for _, tc := range testcases {
   198  		t.Run(tc.name, func(t *testing.T) {
   199  			seg, err := newSegment(tc.input)
   200  			assert.Error(t, err)
   201  			assert.True(t, strings.Contains(err.Error(), tc.errMsg))
   202  			assert.Nil(t, seg)
   203  		})
   204  	}
   205  }
   206  
   207  func makeTestV1Segment(orig *sarama.ConsumerMessage, key string, total, index uint64, version, producerId string) *Segment {
   208  	seg := makeTestSegment(orig, key, total, index)
   209  	seg.version = version
   210  	seg.producerId = producerId
   211  	return seg
   212  }
   213  
   214  func makeTestSegment(orig *sarama.ConsumerMessage, key string, total, index uint64) *Segment {
   215  	return &Segment{
   216  		orig:       orig,
   217  		key:        key,
   218  		total:      total,
   219  		index:      index,
   220  		value:      common.MakeRandomBytes(5),
   221  		version:    "",
   222  		producerId: "",
   223  	}
   224  }
   225  
   226  func Test_insertSegment_Success_OneMessage(t *testing.T) {
   227  	// insert the message segments into the empty buffer in the order of m1s0, m1s1, m1s2
   228  	var buffer [][]*Segment
   229  	var err error
   230  
   231  	msg1Key := "msg-1"
   232  	total := uint64(3)
   233  	m1s0 := makeTestSegment(nil, msg1Key, total, 0)
   234  	m1s1 := makeTestSegment(nil, msg1Key, total, 1)
   235  	m1s2 := makeTestSegment(nil, msg1Key, total, 2)
   236  
   237  	buffer, err = insertSegment(m1s0, buffer)
   238  	assert.NoError(t, err)
   239  	buffer, err = insertSegment(m1s1, buffer)
   240  	assert.NoError(t, err)
   241  	buffer, err = insertSegment(m1s2, buffer)
   242  	assert.NoError(t, err)
   243  
   244  	// expected buffer
   245  	// [m1s0][m1s1][m1s2]
   246  	expected := [][]*Segment{{m1s0, m1s1, m1s2}}
   247  	assert.Equal(t, expected, buffer)
   248  }
   249  
   250  func Test_insertSegment_Success_MultipleMessages(t *testing.T) {
   251  	// insert the message segments into the empty buffer in the order of m1s0, m2s0, m3s0, m2s1, m1s1, m3s1
   252  	var buffer [][]*Segment
   253  	var err error
   254  
   255  	msg1Key := "msg-1"
   256  	total := uint64(3)
   257  	m1s0 := makeTestSegment(nil, msg1Key, total, 0)
   258  	m1s1 := makeTestSegment(nil, msg1Key, total, 1)
   259  
   260  	msg2Key := "msg-2"
   261  	m2s0 := makeTestSegment(nil, msg2Key, total, 0)
   262  	m2s1 := makeTestSegment(nil, msg2Key, total, 1)
   263  
   264  	msg3Key := "msg-3"
   265  	m3s0 := makeTestSegment(nil, msg3Key, total, 0)
   266  	m3s1 := makeTestSegment(nil, msg3Key, total, 1)
   267  
   268  	buffer, err = insertSegment(m1s0, buffer)
   269  	assert.NoError(t, err)
   270  	buffer, err = insertSegment(m2s0, buffer)
   271  	assert.NoError(t, err)
   272  	buffer, err = insertSegment(m3s0, buffer)
   273  	assert.NoError(t, err)
   274  	buffer, err = insertSegment(m2s1, buffer)
   275  	assert.NoError(t, err)
   276  	buffer, err = insertSegment(m1s1, buffer)
   277  	assert.NoError(t, err)
   278  	buffer, err = insertSegment(m3s1, buffer)
   279  	assert.NoError(t, err)
   280  
   281  	// expected buffer
   282  	// [m1s0][m1s1]
   283  	// [m2s0][m2s1]
   284  	// [m3s0][m3s1]
   285  	expected := [][]*Segment{
   286  		{m1s0, m1s1},
   287  		{m2s0, m2s1},
   288  		{m3s0, m3s1},
   289  	}
   290  	assert.Equal(t, expected, buffer)
   291  }
   292  
   293  func Test_insertSegment_Success_DuplicatedMessages(t *testing.T) {
   294  	var buffer [][]*Segment
   295  	var err error
   296  
   297  	msg1Key := "msg-1"
   298  	total := uint64(3)
   299  	m1s0 := makeTestSegment(nil, msg1Key, total, 0)
   300  	m1s1 := makeTestSegment(nil, msg1Key, total, 1)
   301  
   302  	buffer, err = insertSegment(m1s0, buffer)
   303  	assert.NoError(t, err)
   304  	buffer, err = insertSegment(m1s0, buffer)
   305  	assert.NoError(t, err)
   306  	buffer, err = insertSegment(m1s1, buffer)
   307  	assert.NoError(t, err)
   308  
   309  	// expected buffer
   310  	// [m1s0][m1s1]
   311  	expected := [][]*Segment{
   312  		{m1s0, m1s1},
   313  	}
   314  	assert.Equal(t, expected, buffer)
   315  
   316  	msg2Key := "msg-2"
   317  	m2s0 := makeTestSegment(nil, msg2Key, total, 0)
   318  	m2s1 := makeTestSegment(nil, msg2Key, total, 1)
   319  
   320  	buffer, err = insertSegment(m2s0, buffer)
   321  	assert.NoError(t, err)
   322  	buffer, err = insertSegment(m2s1, buffer)
   323  	assert.NoError(t, err)
   324  	buffer, err = insertSegment(m2s0, buffer)
   325  	assert.NoError(t, err)
   326  	buffer, err = insertSegment(m2s1, buffer)
   327  	assert.NoError(t, err)
   328  
   329  	// expected buffer
   330  	// [m1s0][m1s1]
   331  	// [m2s0][m2s1]
   332  	expected = [][]*Segment{
   333  		{m1s0, m1s1},
   334  		{m2s0, m2s1},
   335  	}
   336  	assert.Equal(t, expected, buffer)
   337  }
   338  
   339  func Test_insertSegment_Success_IgnoreAlreadyInsertedSegment(t *testing.T) {
   340  	var buffer [][]*Segment
   341  	var err error
   342  
   343  	msg1Key := "msg-1"
   344  	total := uint64(3)
   345  	m1s1 := makeTestSegment(nil, msg1Key, total, 1)
   346  
   347  	buffer, err = insertSegment(m1s1, buffer)
   348  	assert.NoError(t, err)
   349  
   350  	msg2Key := "msg-2"
   351  	m2s2 := makeTestSegment(nil, msg2Key, total, 2)
   352  
   353  	buffer, err = insertSegment(m2s2, buffer)
   354  	assert.NoError(t, err)
   355  
   356  	// expected empty buffer
   357  	var expected [][]*Segment
   358  	assert.Equal(t, expected, buffer)
   359  }
   360  
   361  func Test_insertSegment_Fail_WrongSegmentError(t *testing.T) {
   362  	var buffer [][]*Segment
   363  	var err error
   364  
   365  	msg1Key := "msg-1"
   366  	total := uint64(3)
   367  	m1s0 := makeTestSegment(nil, msg1Key, total, 0)
   368  	m1s2 := makeTestSegment(nil, msg1Key, total, 2)
   369  
   370  	buffer, err = insertSegment(m1s0, buffer)
   371  	assert.NoError(t, err)
   372  	buffer, err = insertSegment(m1s2, buffer)
   373  	assert.Error(t, err)
   374  	assert.True(t, strings.Contains(err.Error(), missingSegmentErrorMsg))
   375  }
   376  
   377  func TestConsumer_handleBufferedMessages_Success_NotCompleteMessage(t *testing.T) {
   378  	testConsumer := &Consumer{}
   379  
   380  	// not a complete message, so nothing is processed
   381  	m1s0 := makeTestSegment(nil, "msg-1", 2, 0)
   382  	buffer := [][]*Segment{{m1s0}}
   383  	after, err := testConsumer.handleBufferedMessages(buffer)
   384  	assert.NoError(t, err)
   385  	assert.Equal(t, buffer, after)
   386  
   387  	// a complete message in the middle
   388  	m1s0 = makeTestSegment(nil, "msg-1", 2, 0)
   389  	m2s0 := makeTestSegment(nil, "msg-2", 2, 0)
   390  	m2s1 := makeTestSegment(nil, "msg-2", 2, 1)
   391  	buffer = [][]*Segment{{m1s0}, {m2s0, m2s1}}
   392  	after, err = testConsumer.handleBufferedMessages(buffer)
   393  	assert.NoError(t, err)
   394  	assert.Equal(t, buffer, after)
   395  }
   396  
   397  func TestConsumer_handleBufferedMessages_Success(t *testing.T) {
   398  	testTopic := "test-topic"
   399  	testOrig := &sarama.ConsumerMessage{Topic: testTopic}
   400  	testConsumer := &Consumer{
   401  		handlers: make(map[string]TopicHandler),
   402  	}
   403  
   404  	msg1Key := []byte("msg-1")
   405  	msg2Key := []byte("msg-2")
   406  	var msg1Expected []byte
   407  	var msg2Expected []byte
   408  	testConsumer.handlers[testTopic] = func(message *sarama.ConsumerMessage) error {
   409  		if bytes.Equal(message.Key, msg1Key) {
   410  			assert.Equal(t, msg1Expected, message.Value)
   411  		}
   412  
   413  		if bytes.Equal(message.Key, msg2Key) {
   414  			assert.Equal(t, msg2Expected, message.Value)
   415  		}
   416  		return nil
   417  	}
   418  
   419  	emptyBuffer := [][]*Segment{}
   420  
   421  	// a complete message with total 1
   422  	m1s0 := makeTestSegment(testOrig, "msg-1", 1, 0)
   423  	buffer := [][]*Segment{{m1s0}}
   424  	msg1Expected = m1s0.value
   425  	after, err := testConsumer.handleBufferedMessages(buffer)
   426  	assert.NoError(t, err)
   427  	assert.Equal(t, emptyBuffer, after)
   428  
   429  	// a complete message with total 2
   430  	m2s0 := makeTestSegment(testOrig, "msg-2", 2, 0)
   431  	m2s1 := makeTestSegment(testOrig, "msg-2", 2, 1)
   432  	buffer = [][]*Segment{{m2s0, m2s1}}
   433  	msg2Expected = append(m2s0.value, m2s1.value...)
   434  	after, err = testConsumer.handleBufferedMessages(buffer)
   435  	assert.NoError(t, err)
   436  	assert.Equal(t, emptyBuffer, after)
   437  
   438  	// two complete messages
   439  	buffer = [][]*Segment{{m1s0}, {m2s0, m2s1}}
   440  	msg1Expected = m1s0.value
   441  	msg2Expected = append(m2s0.value, m2s1.value...)
   442  	after, err = testConsumer.handleBufferedMessages(buffer)
   443  	assert.NoError(t, err)
   444  	assert.Equal(t, emptyBuffer, after)
   445  }
   446  
   447  func TestConsumer_handleBufferedMessages_Fail(t *testing.T) {
   448  	testTopic := "test-topic"
   449  	testOrig := &sarama.ConsumerMessage{Topic: testTopic}
   450  	testConsumer := &Consumer{
   451  		handlers: make(map[string]TopicHandler),
   452  	}
   453  
   454  	// no handler is added
   455  	m2s0 := makeTestSegment(testOrig, "msg-1", 2, 0)
   456  	m2s1 := makeTestSegment(testOrig, "msg-1", 2, 1)
   457  	buffer := [][]*Segment{{m2s0, m2s1}}
   458  	_, err := testConsumer.handleBufferedMessages(buffer)
   459  	assert.Error(t, err)
   460  	assert.True(t, strings.Contains(err.Error(), noHandlerErrorMsg))
   461  }
   462  
   463  func TestConsumer_updateOffset(t *testing.T) {
   464  	ctrl := gomock.NewController(t)
   465  	defer ctrl.Finish()
   466  	session := mocks.NewMockConsumerGroupSession(ctrl)
   467  
   468  	testTopic := "test-topic"
   469  	testOffset := int64(111)
   470  	testPartition := int32(812)
   471  	testMsg := &sarama.ConsumerMessage{Topic: testTopic, Partition: testPartition, Offset: testOffset}
   472  	testConsumer := &Consumer{}
   473  
   474  	// no segment in the buffer
   475  	session.EXPECT().MarkMessage(gomock.Eq(testMsg), gomock.Eq(""))
   476  	var buffer [][]*Segment
   477  	err := testConsumer.updateOffset(buffer, testMsg, session)
   478  	assert.NoError(t, err)
   479  
   480  	// there is a segment in the buffer
   481  	seg := makeTestSegment(testMsg, "msg-1", 3, 0)
   482  	session.EXPECT().MarkOffset(gomock.Eq(seg.orig.Topic), gomock.Eq(seg.orig.Partition), gomock.Eq(seg.orig.Offset), gomock.Eq(""))
   483  	buffer = [][]*Segment{{seg}}
   484  	err = testConsumer.updateOffset(buffer, testMsg, session)
   485  	assert.NoError(t, err)
   486  
   487  	// wrong buffer
   488  	buffer = [][]*Segment{{}}
   489  	err = testConsumer.updateOffset(buffer, testMsg, session)
   490  	assert.Error(t, err)
   491  	assert.True(t, strings.Contains(err.Error(), emptySegmentErrorMsg))
   492  }
   493  
   494  func getTestConsumer() (string, *Consumer) {
   495  	testTopic := "test-topic"
   496  	testConsumer := &Consumer{
   497  		handlers: make(map[string]TopicHandler),
   498  	}
   499  
   500  	testConsumer.handlers[testTopic] = func(message *sarama.ConsumerMessage) error {
   501  		return nil
   502  	}
   503  	return testTopic, testConsumer
   504  }
   505  
   506  func Test_V1Segment_MultiProducers(t *testing.T) {
   507  	{ // Legacy segments test
   508  		var buffer [][]*Segment
   509  		var err error
   510  
   511  		msgKey := "msg"
   512  		total := uint64(3)
   513  		indices := []uint64{0, 1, 0, 2, 1, 0, 2, 1, 1 /* duplicated */, 2}
   514  
   515  		topic, consumer := getTestConsumer()
   516  
   517  		var msgs []*Segment
   518  		for _, idx := range indices {
   519  			msgs = append(msgs, makeTestSegment(&sarama.ConsumerMessage{Topic: topic}, msgKey, total, idx))
   520  		}
   521  
   522  		for idx, msg := range msgs {
   523  			buffer, err = insertSegment(msg, buffer)
   524  			if idx < 6 {
   525  				assert.NoError(t, err)
   526  			} else if idx == 6 {
   527  				assert.Error(t, err)
   528  				assert.True(t, strings.Contains(err.Error(), missingSegmentErrorMsg))
   529  				break
   530  			}
   531  			buffer, err = consumer.handleBufferedMessages(buffer)
   532  			assert.NoError(t, err)
   533  		}
   534  	}
   535  
   536  	{ // V1 segments test
   537  		var buffer [][]*Segment
   538  		var err error
   539  
   540  		msgKey := "msg"
   541  		total := uint64(3)
   542  		producerId := []string{"1", "1", "2", "1", "2", "3", "2", "3", "3", "3"}
   543  		indices := []uint64{0, 1, 0, 2, 1, 0, 2, 1, 1 /* duplicated */, 2}
   544  
   545  		topic, consumer := getTestConsumer()
   546  
   547  		var msgs []*Segment
   548  		for pi, si := range indices {
   549  			msgs = append(msgs, makeTestV1Segment(&sarama.ConsumerMessage{Topic: topic}, msgKey, total, si, MsgVersion1_0, producerId[pi]))
   550  		}
   551  
   552  		for _, msg := range msgs {
   553  			buffer, err = insertSegment(msg, buffer)
   554  			assert.NoError(t, err)
   555  			buffer, err = consumer.handleBufferedMessages(buffer)
   556  			assert.NoError(t, err)
   557  		}
   558  	}
   559  }
   560  
   561  func TestConsumer_handleError(t *testing.T) {
   562  	ctrl := gomock.NewController(t)
   563  	defer ctrl.Finish()
   564  	testSegment := &Segment{
   565  		orig: &sarama.ConsumerMessage{
   566  			Topic:     "test-topic",
   567  			Partition: int32(1),
   568  			Offset:    int64(99),
   569  		},
   570  	}
   571  
   572  	testSegment2 := &Segment{
   573  		orig: &sarama.ConsumerMessage{
   574  			Topic:     "test-topic",
   575  			Partition: int32(1),
   576  			Offset:    int64(100),
   577  		},
   578  	}
   579  
   580  	session := mocks.NewMockConsumerGroupSession(ctrl)
   581  	parentErr := errors.New("parent error")
   582  	callbackErr := errors.New("callback error")
   583  
   584  	tests := []struct {
   585  		name      string
   586  		setup     func()
   587  		callback  func(s string) error
   588  		buffer    [][]*Segment
   589  		parentErr error
   590  		expected  error
   591  	}{
   592  		{
   593  			"no_item_in_buffer",
   594  			func() {},
   595  			func(s string) error { panic("should not be called") },
   596  			[][]*Segment{},
   597  			parentErr,
   598  			parentErr,
   599  		},
   600  		{
   601  			"no_callback",
   602  			func() {},
   603  			nil,
   604  			[][]*Segment{{testSegment}},
   605  			parentErr,
   606  			parentErr,
   607  		},
   608  		{
   609  			"callback_success_an_item_in_buffer",
   610  			func() { session.EXPECT().MarkMessage(gomock.Eq(testSegment.orig), gomock.Eq("")).Times(1) },
   611  			func(s string) error { return nil },
   612  			[][]*Segment{{testSegment}},
   613  			parentErr,
   614  			nil,
   615  		},
   616  		{
   617  			"callback_success_two_items_in_buffer",
   618  			func() {
   619  				session.EXPECT().MarkOffset(gomock.Eq(testSegment2.orig.Topic), gomock.Eq(testSegment2.orig.Partition), gomock.Eq(testSegment2.orig.Offset), gomock.Eq("")).Times(1)
   620  			},
   621  			func(s string) error { return nil },
   622  			[][]*Segment{{testSegment}, {testSegment2}},
   623  			parentErr,
   624  			nil,
   625  		},
   626  		{
   627  			"callback_failure",
   628  			func() {},
   629  			func(s string) error { return callbackErr },
   630  			[][]*Segment{{testSegment}, {testSegment2}},
   631  			parentErr,
   632  			callbackErr,
   633  		},
   634  	}
   635  	for _, tt := range tests {
   636  		t.Run(tt.name, func(t *testing.T) {
   637  			c := &Consumer{}
   638  			c.config = GetDefaultKafkaConfig()
   639  			c.config.ErrCallback = tt.callback
   640  			tt.setup()
   641  			if err := c.handleError(tt.buffer, session, tt.parentErr); err != tt.expected {
   642  				t.Errorf("handleError() error = %v, wantErr %v", err, tt.expected)
   643  			}
   644  		})
   645  	}
   646  }
   647  
   648  func TestConsumer_renewExpireMsg(t *testing.T) {
   649  	testTimer := time.NewTimer(1 * time.Second)
   650  	testTimer.Stop()
   651  
   652  	oldMsg := &sarama.ConsumerMessage{Key: []byte("old")}
   653  	newMsg := &sarama.ConsumerMessage{Key: []byte("new")}
   654  
   655  	type args struct {
   656  		buffer    [][]*Segment
   657  		timer     *time.Timer
   658  		oldestMsg *sarama.ConsumerMessage
   659  	}
   660  	tests := []struct {
   661  		name   string
   662  		config *KafkaConfig
   663  		args   args
   664  		want   *sarama.ConsumerMessage
   665  	}{
   666  		{
   667  			"no_expire_option",
   668  			&KafkaConfig{ExpirationTime: time.Duration(0)},
   669  			args{},
   670  			nil,
   671  		},
   672  		{
   673  			"all_handled",
   674  			&KafkaConfig{ExpirationTime: time.Duration(1)},
   675  			args{
   676  				[][]*Segment{},
   677  				testTimer,
   678  				oldMsg,
   679  			},
   680  			nil,
   681  		},
   682  		{
   683  			"oldest_handled",
   684  			&KafkaConfig{ExpirationTime: time.Duration(1)},
   685  			args{
   686  				[][]*Segment{{&Segment{orig: newMsg}}},
   687  				testTimer,
   688  				oldMsg,
   689  			},
   690  			newMsg,
   691  		},
   692  		{
   693  			"oldest_not_handled",
   694  			&KafkaConfig{ExpirationTime: time.Duration(1)},
   695  			args{
   696  				[][]*Segment{{&Segment{orig: oldMsg}}},
   697  				testTimer,
   698  				oldMsg,
   699  			},
   700  			oldMsg,
   701  		},
   702  	}
   703  	for _, tt := range tests {
   704  		t.Run(tt.name, func(t *testing.T) {
   705  			c := &Consumer{
   706  				config: tt.config,
   707  			}
   708  			if got := c.resetTimer(tt.args.buffer, tt.args.timer, tt.args.oldestMsg); !reflect.DeepEqual(got, tt.want) {
   709  				t.Errorf("resetTimer() = %v, want %v", got, tt.want)
   710  			}
   711  		})
   712  	}
   713  }