trpc.group/trpc-go/trpc-go@v1.0.3/internal/writev/buffer_test.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package writev 15 16 import ( 17 "errors" 18 "fmt" 19 "runtime" 20 "sync" 21 "sync/atomic" 22 "testing" 23 "time" 24 25 "github.com/stretchr/testify/assert" 26 ) 27 28 var ( 29 errForceError = errors.New("force error") 30 defaultSize = 128 31 defaultMsg = []byte("Hello World!!") 32 ) 33 34 type fakeReadWriter struct { 35 read chan []byte 36 sleep bool 37 err bool 38 } 39 40 // Write simulates a write operation. 41 func (f *fakeReadWriter) Write(p []byte) (n int, err error) { 42 if f.err { 43 return 0, errForceError 44 } 45 if f.sleep { 46 time.Sleep(time.Millisecond) 47 } 48 f.read <- p 49 return len(p), nil 50 } 51 52 // Read simulates read operation. 53 func (f *fakeReadWriter) Read() []byte { 54 return <-f.read 55 } 56 57 func TestBufferWrite(t *testing.T) { 58 done := make(chan struct{}, 1) 59 rw := &fakeReadWriter{read: make(chan []byte, defaultSize)} 60 buffer := NewBuffer() 61 buffer.Start(rw, done) 62 63 _, err := buffer.Write(defaultMsg) 64 assert.Nil(t, err) 65 rsp := rw.Read() 66 assert.Equal(t, defaultMsg, rsp) 67 assert.Equal(t, done, buffer.Done()) 68 69 buffer.SetQueueStopped(true) 70 _, err = buffer.Write(defaultMsg) 71 assert.Equal(t, ErrStopped, err) 72 73 close(done) 74 time.Sleep(time.Millisecond) 75 assert.Equal(t, ErrAskQuit, buffer.Error()) 76 } 77 78 func TestBufferWritev(t *testing.T) { 79 done := make(chan struct{}, 1) 80 rw := &fakeReadWriter{read: make(chan []byte, defaultSize)} 81 buffer := NewBuffer() 82 buffer.Start(rw, done) 83 defer close(done) 84 85 for i := 0; i < 10; i++ { 86 _, err := buffer.Write([]byte(fmt.Sprintf("hello world %d\n", i))) 87 assert.Nil(t, err) 88 } 89 for i := 0; i < 10; i++ { 90 rsp := rw.Read() 91 assert.Equal(t, fmt.Sprintf("hello world %d\n", i), string(rsp)) 92 } 93 } 94 95 func TestBufferWriteFull(t *testing.T) { 96 done := make(chan struct{}, 1) 97 rw := &fakeReadWriter{read: make(chan []byte, defaultSize), sleep: true} 98 buffer := NewBuffer(WithDropFull(true), WithBufferSize(4)) 99 buffer.Start(rw, done) 100 defer close(done) 101 for { 102 _, err := buffer.Write(defaultMsg) 103 if err != nil { 104 assert.NotNil(t, err) 105 return 106 } 107 } 108 } 109 110 func TestBufferQuitHandle(t *testing.T) { 111 done := make(chan struct{}, 1) 112 rw := &fakeReadWriter{read: make(chan []byte, defaultSize), err: true} 113 value := "abc" 114 handler := func(buffer *Buffer) { 115 value = "efg" 116 buffer.SetQueueStopped(true) 117 } 118 buffer := NewBuffer(WithDropFull(true), WithBufferSize(8), WithQuitHandler(handler)) 119 buffer.Start(rw, done) 120 defer close(done) 121 122 _, err := buffer.Write(defaultMsg) 123 assert.Nil(t, err) 124 time.Sleep(time.Millisecond) 125 assert.Equal(t, "efg", value) 126 assert.Equal(t, errForceError, buffer.Error()) 127 128 _, err = buffer.Write(defaultMsg) 129 assert.Equal(t, errForceError, err) 130 } 131 132 func TestBufferReStart(t *testing.T) { 133 done := make(chan struct{}, 1) 134 rw := &fakeReadWriter{read: make(chan []byte, defaultSize), err: true} 135 136 buffer := NewBuffer() 137 buffer.Start(rw, done) 138 close(done) 139 time.Sleep(time.Millisecond) 140 newdone := make(chan struct{}, 1) 141 buffer = buffer.Restart(rw, newdone) 142 defer close(newdone) 143 144 _, err := buffer.Write(defaultMsg) 145 assert.Nil(t, err) 146 } 147 148 type fakeWriter struct { 149 rcv uint32 150 } 151 152 // Write simulates a write operation. 153 func (f *fakeWriter) Write(p []byte) (n int, err error) { 154 atomic.AddUint32(&f.rcv, 1) 155 return len(p), nil 156 } 157 158 func (f *fakeWriter) getReceives() uint32 { 159 return f.rcv 160 } 161 162 func TestConCurrentWrite(t *testing.T) { 163 w := &fakeWriter{} 164 done := make(chan struct{}, 1) 165 buffer := NewBuffer() 166 buffer.Start(w, done) 167 defer close(done) 168 cpus := runtime.NumCPU() 169 170 wg := &sync.WaitGroup{} 171 for i := 0; i < cpus; i++ { 172 wg.Add(1) 173 go doWriteBuffer(buffer, wg, 10000) 174 } 175 wg.Wait() 176 // wait for the package to complete. 177 for { 178 if buffer.queue.IsEmpty() { 179 break 180 } 181 runtime.Gosched() 182 } 183 time.Sleep(time.Millisecond) 184 assert.Equal(t, uint32(10000*cpus), w.getReceives()) 185 } 186 187 // BenchmarkWriteBuffer tests the concurrent performance of WriteBuffer. 188 func BenchmarkWriteBuffer(b *testing.B) { 189 w := &fakeWriter{} 190 done := make(chan struct{}, 1) 191 buffer := NewBuffer() 192 buffer.Start(w, done) 193 defer close(done) 194 cpus := runtime.NumCPU() * 10 195 wg := &sync.WaitGroup{} 196 197 b.SetBytes(1) 198 b.ReportAllocs() 199 b.ResetTimer() 200 for j := 0; j < cpus; j++ { 201 wg.Add(1) 202 go doWriteBuffer(buffer, wg, b.N) 203 } 204 wg.Wait() 205 b.StopTimer() 206 } 207 208 func doWriteBuffer(b *Buffer, wg *sync.WaitGroup, num int) { 209 defer wg.Done() 210 for { 211 if _, err := b.Write(defaultMsg); err == nil { 212 num-- 213 } 214 if num <= 0 { 215 return 216 } 217 } 218 }