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  }