github.com/micro/go-micro/v2@v2.9.1/server/rpc_stream_test.go (about)

     1  package server
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"math/rand"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	"github.com/micro/go-micro/v2/codec/json"
    14  	protoCodec "github.com/micro/go-micro/v2/codec/proto"
    15  )
    16  
    17  // protoStruct implements proto.Message
    18  type protoStruct struct {
    19  	Payload string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
    20  }
    21  
    22  func (m *protoStruct) Reset()         { *m = protoStruct{} }
    23  func (m *protoStruct) String() string { return proto.CompactTextString(m) }
    24  func (*protoStruct) ProtoMessage()    {}
    25  
    26  // safeBuffer throws away everything and wont Read data back
    27  type safeBuffer struct {
    28  	sync.RWMutex
    29  	buf []byte
    30  	off int
    31  }
    32  
    33  func (b *safeBuffer) Write(p []byte) (n int, err error) {
    34  	if len(p) == 0 {
    35  		return 0, nil
    36  	}
    37  	// Cannot retain p, so we must copy it:
    38  	p2 := make([]byte, len(p))
    39  	copy(p2, p)
    40  	b.Lock()
    41  	b.buf = append(b.buf, p2...)
    42  	b.Unlock()
    43  	return len(p2), nil
    44  }
    45  
    46  func (b *safeBuffer) Read(p []byte) (n int, err error) {
    47  	if len(p) == 0 {
    48  		return 0, nil
    49  	}
    50  	b.RLock()
    51  	n = copy(p, b.buf[b.off:])
    52  	b.RUnlock()
    53  	if n == 0 {
    54  		return 0, io.EOF
    55  	}
    56  	b.off += n
    57  	return n, nil
    58  }
    59  
    60  func (b *safeBuffer) Close() error {
    61  	return nil
    62  }
    63  
    64  func TestRPCStream_Sequence(t *testing.T) {
    65  	buffer := new(bytes.Buffer)
    66  	rwc := readWriteCloser{
    67  		rbuf: buffer,
    68  		wbuf: buffer,
    69  	}
    70  	codec := json.NewCodec(&rwc)
    71  	streamServer := rpcStream{
    72  		codec: codec,
    73  		request: &rpcRequest{
    74  			codec: codec,
    75  		},
    76  	}
    77  
    78  	// Check if sequence is correct
    79  	for i := 0; i < 1000; i++ {
    80  		if err := streamServer.Send(fmt.Sprintf(`{"test":"value %d"}`, i)); err != nil {
    81  			t.Errorf("Unexpected Send error: %s", err)
    82  		}
    83  	}
    84  
    85  	for i := 0; i < 1000; i++ {
    86  		var msg string
    87  		if err := streamServer.Recv(&msg); err != nil {
    88  			t.Errorf("Unexpected Recv error: %s", err)
    89  		}
    90  		if msg != fmt.Sprintf(`{"test":"value %d"}`, i) {
    91  			t.Errorf("Unexpected msg: %s", msg)
    92  		}
    93  	}
    94  }
    95  
    96  func TestRPCStream_Concurrency(t *testing.T) {
    97  	buffer := new(safeBuffer)
    98  	codec := protoCodec.NewCodec(buffer)
    99  	streamServer := rpcStream{
   100  		codec: codec,
   101  		request: &rpcRequest{
   102  			codec: codec,
   103  		},
   104  	}
   105  
   106  	var wg sync.WaitGroup
   107  	// Check if race conditions happen
   108  	for i := 0; i < 10; i++ {
   109  		wg.Add(2)
   110  
   111  		go func() {
   112  			for i := 0; i < 50; i++ {
   113  				msg := protoStruct{Payload: "test"}
   114  				<-time.After(time.Duration(rand.Intn(50)) * time.Millisecond)
   115  				if err := streamServer.Send(msg); err != nil {
   116  					t.Errorf("Unexpected Send error: %s", err)
   117  				}
   118  			}
   119  			wg.Done()
   120  		}()
   121  
   122  		go func() {
   123  			for i := 0; i < 50; i++ {
   124  				<-time.After(time.Duration(rand.Intn(50)) * time.Millisecond)
   125  				if err := streamServer.Recv(&protoStruct{}); err != nil {
   126  					t.Errorf("Unexpected Recv error: %s", err)
   127  				}
   128  			}
   129  			wg.Done()
   130  		}()
   131  	}
   132  	wg.Wait()
   133  }