github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/topic/topicreaderinternal/message_content_pool_test.go (about) 1 package topicreaderinternal 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "testing" 8 9 "github.com/stretchr/testify/require" 10 "go.uber.org/mock/gomock" 11 12 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" 13 ) 14 15 func BenchmarkConsumeContent(b *testing.B) { 16 b.ReportAllocs() 17 content := []byte("asd") 18 reader := bytes.NewReader(content) 19 msg := PublicMessage{data: newOneTimeReader(reader)} 20 for i := 0; i < b.N; i++ { 21 reader.Reset(content) 22 msg.dataConsumed = false 23 msg.data = newOneTimeReader(reader) 24 err := msg.UnmarshalTo(emptyConsumer{}) 25 if err != nil { 26 b.Fatal() 27 } 28 } 29 } 30 31 func TestCallbackOnReaderContent(t *testing.T) { 32 expectedData := []byte(`asdf`) 33 newReader := func() io.Reader { 34 return bytes.NewReader(expectedData) 35 } 36 37 t.Run("ZeroEstimatedSize", func(t *testing.T) { 38 mc := gomock.NewController(t) 39 p := NewMockPool(mc) 40 p.EXPECT().Get().Return(nil) 41 p.EXPECT().Put(gomock.Any()).Do(func(buf *bytes.Buffer) { 42 require.NotNil(t, buf) 43 require.Equal(t, 0, buf.Len()) 44 require.Equal(t, minInitializeBufferSize, buf.Cap()) 45 }) 46 47 called := false 48 err := callbackOnReaderContent(p, newReader(), 0, testFuncConsumer(func(data []byte) error { 49 called = true 50 require.Equal(t, expectedData, data) 51 52 return nil 53 })) 54 require.NoError(t, err) 55 require.True(t, called) 56 }) 57 t.Run("MiddleEstimatedSize", func(t *testing.T) { 58 estimatedSize := minInitializeBufferSize + 10 59 60 mc := gomock.NewController(t) 61 p := NewMockPool(mc) 62 p.EXPECT().Get().Return(nil).Times(2) 63 64 var targetCapacity int 65 p.EXPECT().Put(gomock.Any()).Do(func(buf *bytes.Buffer) { 66 targetCapacity = buf.Cap() 67 }) 68 69 p.EXPECT().Put(gomock.Any()).Do(func(buf *bytes.Buffer) { 70 require.NotNil(t, buf) 71 require.Equal(t, 0, buf.Len()) 72 73 // check about target capacity same as without read - that mean no reallocations while read 74 require.Equal(t, targetCapacity, buf.Cap()) 75 }) 76 77 // first call with empty reader - for check internal capacity without reallocation 78 _ = callbackOnReaderContent(p, ErrReader(io.EOF), estimatedSize, testFuncConsumer(func(data []byte) error { 79 require.Empty(t, data) 80 81 return nil 82 })) 83 84 // real call 85 called := false 86 err := callbackOnReaderContent(p, newReader(), estimatedSize, testFuncConsumer(func(data []byte) error { 87 require.Equal(t, expectedData, data) 88 called = true 89 90 return nil 91 })) 92 require.NoError(t, err) 93 require.True(t, called) 94 }) 95 t.Run("LargeEstimatedSize", func(t *testing.T) { 96 mc := gomock.NewController(t) 97 p := NewMockPool(mc) 98 p.EXPECT().Get().Return(nil) 99 p.EXPECT().Put(gomock.Any()).Do(func(buf *bytes.Buffer) { 100 require.NotNil(t, buf) 101 require.Equal(t, 0, buf.Len()) 102 require.Equal(t, maxInitialBufferSize, buf.Cap()) 103 }) 104 105 called := false 106 err := callbackOnReaderContent(p, newReader(), maxInitialBufferSize+10, testFuncConsumer(func(data []byte) error { 107 require.Equal(t, expectedData, data) 108 called = true 109 110 return nil 111 })) 112 require.NoError(t, err) 113 require.True(t, called) 114 }) 115 t.Run("UseBufferFromPool", func(t *testing.T) { 116 poolBuf := &bytes.Buffer{} 117 mc := gomock.NewController(t) 118 p := NewMockPool(mc) 119 p.EXPECT().Get().Return(poolBuf) 120 p.EXPECT().Put(gomock.Any()).Do(func(buf *bytes.Buffer) { 121 require.Same(t, poolBuf, buf) 122 }) 123 124 called := false 125 err := callbackOnReaderContent(p, newReader(), 0, testFuncConsumer(func(data []byte) error { 126 require.Equal(t, expectedData, data) 127 called = true 128 129 return nil 130 })) 131 require.NoError(t, err) 132 require.True(t, called) 133 }) 134 t.Run("ReturnErrorFromReader", func(t *testing.T) { 135 testErr := errors.New("test") 136 err := callbackOnReaderContent(globalReadMessagePool, ErrReader(testErr), 0, nil) 137 require.ErrorIs(t, err, testErr) 138 require.False(t, xerrors.IsYdb(err)) 139 }) 140 t.Run("ReturnErrorFromUnmarshal", func(t *testing.T) { 141 testErr := errors.New("test") 142 err := callbackOnReaderContent( 143 globalReadMessagePool, 144 ErrReader(io.EOF), 145 0, 146 testFuncConsumer(func(data []byte) error { 147 return testErr 148 }), 149 ) 150 require.ErrorIs(t, err, testErr) 151 require.False(t, xerrors.IsYdb(err)) 152 }) 153 } 154 155 type emptyConsumer struct{} 156 157 func (emptyConsumer) UnmarshalYDBTopicMessage([]byte) error { 158 return nil 159 } 160 161 type testFuncConsumer func([]byte) error 162 163 func (c testFuncConsumer) UnmarshalYDBTopicMessage(data []byte) error { 164 return c(data) 165 } 166 167 // ErrReader returns an io.Reader that returns 0, err from all Read calls. 168 // copy for use with go pre 1.16 169 func ErrReader(err error) io.Reader { 170 return &errReader{err: err} 171 } 172 173 type errReader struct { 174 err error 175 } 176 177 func (r *errReader) Read(p []byte) (int, error) { 178 return 0, r.err 179 }