From ceb2374bebde8ba1c08d4ffafae2530039be0aa8 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 10:53:43 +0800 Subject: [PATCH 01/13] chore: fix ci --- client/stream_test.go | 2 +- pkg/rpcinfo/mocks_test.go | 4 ++++ pkg/streamx/provider/ttstream/client_trans_pool.go | 7 ++++++- .../provider/ttstream/client_trans_pool_longconn.go | 4 +--- pkg/streamx/provider/ttstream/client_trans_pool_mux.go | 2 +- .../provider/ttstream/client_trans_pool_shortconn.go | 3 +-- pkg/streamx/provider/ttstream/ttstream_error_test.go | 2 -- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/client/stream_test.go b/client/stream_test.go index 9c07647d2a..0dfee45a4c 100644 --- a/client/stream_test.go +++ b/client/stream_test.go @@ -104,7 +104,7 @@ func TestStreaming(t *testing.T) { cliInfo.ConnPool = connpool s, cr, _ := remotecli.NewStream(ctx, mockRPCInfo, new(mocks.MockCliTransHandler), cliInfo) stream := newStream( - s, cr, kc, mockRPCInfo, serviceinfo.StreamingBidirectional, + s.(streaming.Stream), cr, kc, mockRPCInfo, serviceinfo.StreamingBidirectional, func(stream streaming.Stream, message interface{}) (err error) { return stream.SendMsg(message) }, diff --git a/pkg/rpcinfo/mocks_test.go b/pkg/rpcinfo/mocks_test.go index 781b6b360f..c0033bbd7e 100644 --- a/pkg/rpcinfo/mocks_test.go +++ b/pkg/rpcinfo/mocks_test.go @@ -90,6 +90,10 @@ func (m *MockRPCConfig) TransportProtocol() (r transport.Protocol) { return } +func (m *MockRPCConfig) StreamRecvTimeout() time.Duration { + return time.Duration(0) +} + type MockRPCStats struct{} func (m *MockRPCStats) Record(context.Context, stats.Event, stats.Status, string) {} diff --git a/pkg/streamx/provider/ttstream/client_trans_pool.go b/pkg/streamx/provider/ttstream/client_trans_pool.go index f694b9db3c..261052deab 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool.go @@ -16,7 +16,12 @@ package ttstream -import "github.com/cloudwego/kitex/pkg/serviceinfo" +import ( + "github.com/cloudwego/kitex/pkg/serviceinfo" + "github.com/cloudwego/netpoll" +) + +var dialer = netpoll.NewDialer() type transPool interface { Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (trans *transport, err error) diff --git a/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go b/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go index 3b3dff2750..47e9d9e11e 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go @@ -19,8 +19,6 @@ package ttstream import ( "time" - "github.com/cloudwego/netpoll" - "github.com/cloudwego/kitex/pkg/serviceinfo" "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream/container" ) @@ -61,7 +59,7 @@ func (c *longConnTransPool) Get(sinfo *serviceinfo.ServiceInfo, network string, } // create new connection - conn, err := netpoll.DialConnection(network, addr, time.Second) + conn, err := dialer.DialConnection(network, addr, time.Second) if err != nil { return nil, err } diff --git a/pkg/streamx/provider/ttstream/client_trans_pool_mux.go b/pkg/streamx/provider/ttstream/client_trans_pool_mux.go index dfdf534dcf..441fb02135 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool_mux.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool_mux.go @@ -53,7 +53,7 @@ func (tl *muxTransList) Get(sinfo *serviceinfo.ServiceInfo, network string, addr return trans, nil } - conn, err := netpoll.DialConnection(network, addr, time.Second) + conn, err := dialer.DialConnection(network, addr, time.Second) if err != nil { return nil, err } diff --git a/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go b/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go index 37c803b3c7..5346273847 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go @@ -20,7 +20,6 @@ import ( "time" "github.com/cloudwego/kitex/pkg/serviceinfo" - "github.com/cloudwego/netpoll" ) func newShortConnTransPool() transPool { @@ -31,7 +30,7 @@ type shortConnTransPool struct{} func (c *shortConnTransPool) Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (*transport, error) { // create new connection - conn, err := netpoll.DialConnection(network, addr, time.Second) + conn, err := dialer.DialConnection(network, addr, time.Second) if err != nil { return nil, err } diff --git a/pkg/streamx/provider/ttstream/ttstream_error_test.go b/pkg/streamx/provider/ttstream/ttstream_error_test.go index 7153bd60c3..70262208e4 100644 --- a/pkg/streamx/provider/ttstream/ttstream_error_test.go +++ b/pkg/streamx/provider/ttstream/ttstream_error_test.go @@ -11,7 +11,6 @@ import ( "github.com/cloudwego/kitex/client/streamxclient" "github.com/cloudwego/kitex/internal/test" "github.com/cloudwego/kitex/pkg/kerrors" - "github.com/cloudwego/kitex/pkg/klog" "github.com/cloudwego/kitex/pkg/remote" "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream" "github.com/cloudwego/kitex/server" @@ -48,7 +47,6 @@ func assertBizErr(t *testing.T, err error) { } func TestTTHeaderStreamingErrorHandling(t *testing.T) { - klog.SetLevel(klog.LevelDebug) var addr = test.GetLocalAddress() ln, err := netpoll.CreateListener("tcp", addr) test.Assert(t, err == nil, err) From 2ba9afdac5fb0d79fdeb51b8711a8bd718adbd59 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 11:29:43 +0800 Subject: [PATCH 02/13] chore: fix lint --- client/client.go | 1 - pkg/remote/trans/streamx/server_handler.go | 5 --- pkg/streamx/provider/jsonrpc/protocol.go | 1 + .../provider/ttstream/server_provider.go | 35 ++++++++++++------- pkg/streamx/provider/ttstream/stream.go | 28 --------------- .../provider/ttstream/ttstream_client_test.go | 1 - 6 files changed, 23 insertions(+), 48 deletions(-) diff --git a/client/client.go b/client/client.go index 03cc7cad49..adef12ac6b 100644 --- a/client/client.go +++ b/client/client.go @@ -74,7 +74,6 @@ type kClient struct { sEps endpoint.Endpoint // streamx - sxEps endpoint.Endpoint sxStreamMW streamx.StreamMiddleware sxStreamRecvMW streamx.StreamRecvMiddleware sxStreamSendMW streamx.StreamSendMiddleware diff --git a/pkg/remote/trans/streamx/server_handler.go b/pkg/remote/trans/streamx/server_handler.go index 84132bdcd7..4db789d232 100644 --- a/pkg/remote/trans/streamx/server_handler.go +++ b/pkg/remote/trans/streamx/server_handler.go @@ -20,7 +20,6 @@ import ( "context" "errors" "io" - "log" "net" "runtime/debug" "time" @@ -139,13 +138,9 @@ func (t *svrTransHandler) OnStream(ctx context.Context, conn net.Conn, ss stream if mutableTo := rpcinfo.AsMutableEndpointInfo(ri.To()); mutableTo != nil { _ = mutableTo.SetMethod(ss.Method()) } - //_ = rpcinfo.AsMutableRPCConfig(ri.Config()).SetTransportProtocol(transport.JSONRPC) ctx = t.startTracer(ctx, ri) defer func() { - if err != nil { - log.Println("OnStream failed: ", err) - } panicErr := recover() if panicErr != nil { if conn != nil { diff --git a/pkg/streamx/provider/jsonrpc/protocol.go b/pkg/streamx/provider/jsonrpc/protocol.go index 3d8654ea29..b3f528111d 100644 --- a/pkg/streamx/provider/jsonrpc/protocol.go +++ b/pkg/streamx/provider/jsonrpc/protocol.go @@ -115,6 +115,7 @@ func EncodeFrame(writer io.Writer, frame Frame) (err error) { offset += len(frame.method) copy(data[offset:offset+len(frame.payload)], frame.payload) offset += len(frame.payload) + _ = offset idx := 0 for idx < len(data) { diff --git a/pkg/streamx/provider/ttstream/server_provider.go b/pkg/streamx/provider/ttstream/server_provider.go index 7c9add2f80..07d5c0d72f 100644 --- a/pkg/streamx/provider/ttstream/server_provider.go +++ b/pkg/streamx/provider/ttstream/server_provider.go @@ -96,24 +96,33 @@ func (s serverProvider) OnStreamFinish(ctx context.Context, ss streamx.ServerStr sst := ss.(*serverStream) var exception tException if err != nil { - switch err.(type) { - case tException: - exception = err.(tException) + switch terr := err.(type) { case kerrors.BizStatusErrorIface: - bizErr := err.(kerrors.BizStatusErrorIface) - sst.appendTrailer( - "biz-status", strconv.Itoa(int(bizErr.BizStatusCode())), - "biz-message", bizErr.BizMessage(), - ) - if bizErr.BizExtra() != nil { - extra, _ := utils.Map2JSONStr(bizErr.BizExtra()) - sst.appendTrailer("biz-extra", extra) + bizStatus := strconv.Itoa(int(terr.BizStatusCode())) + bizMsg := terr.BizMessage() + if terr.BizExtra() == nil { + err = sst.writeTrailer(streamx.Trailer{ + "biz-status": bizStatus, + "biz-message": bizMsg, + }) + } else { + bizExtra, _ := utils.Map2JSONStr(terr.BizExtra()) + err = sst.writeTrailer(streamx.Trailer{ + "biz-status": bizStatus, + "biz-message": bizMsg, + "biz-extra": bizExtra, + }) + } + if err != nil { + return nil, err } + case tException: + exception = terr default: - exception = thrift.NewApplicationException(remote.InternalError, err.Error()) + exception = thrift.NewApplicationException(remote.InternalError, terr.Error()) } } - if err := sst.close(exception); err != nil { + if err = sst.close(exception); err != nil { return nil, err } diff --git a/pkg/streamx/provider/ttstream/stream.go b/pkg/streamx/provider/ttstream/stream.go index f426ed3bf7..d0de8bf45e 100644 --- a/pkg/streamx/provider/ttstream/stream.go +++ b/pkg/streamx/provider/ttstream/stream.go @@ -129,14 +129,6 @@ func (s *stream) readHeader(hd streamx.Header) (err error) { return nil } -// setHeader use the hd as the underlying header -func (s *stream) setHeader(hd streamx.Header) { - if hd != nil { - s.wheader = hd - } - return -} - // writeHeader copy kvs into s.wheader func (s *stream) writeHeader(hd streamx.Header) error { if s.wheader == nil { @@ -205,21 +197,6 @@ func (s *stream) writeTrailer(tl streamx.Trailer) (err error) { return nil } -func (s *stream) appendTrailer(kvs ...string) (err error) { - if len(kvs)%2 != 0 { - return fmt.Errorf("got the odd number of input kvs for Trailer: %d", len(kvs)) - } - var key string - for i, str := range kvs { - if i%2 == 0 { - key = str - continue - } - s.wtrailer[key] = str - } - return nil -} - func (s *stream) sendTrailer(ctx context.Context, ex tException) (err error) { if !atomic.CompareAndSwapInt32(&s.selfEOF, 0, 1) { return nil @@ -233,11 +210,6 @@ func (s *stream) sendTrailer(ctx context.Context, ex tException) (err error) { return s.trans.streamCloseSend(s.sid, s.method, wtrailer, ex) } -func (s *stream) finished() bool { - return atomic.LoadInt32(&s.peerEOF) == 1 && - atomic.LoadInt32(&s.selfEOF) == 1 -} - func (s *stream) setRecvTimeout(timeout time.Duration) { if timeout <= 0 { return diff --git a/pkg/streamx/provider/ttstream/ttstream_client_test.go b/pkg/streamx/provider/ttstream/ttstream_client_test.go index 6f918c1d56..0e11434e73 100644 --- a/pkg/streamx/provider/ttstream/ttstream_client_test.go +++ b/pkg/streamx/provider/ttstream/ttstream_client_test.go @@ -574,7 +574,6 @@ func TestTTHeaderStreamingServerGoroutines(t *testing.T) { for i := 0; i < streams; i++ { streamList[i] = nil } - streamList = nil for ngs-oldNGs > 10 { runtime.GC() ngs = runtime.NumGoroutine() From 11d5130d8c6643024ab520cad9dd124d8d628e76 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 11:50:18 +0800 Subject: [PATCH 03/13] chore: fix lint --- pkg/streamx/header_trailer.go | 6 ++-- .../provider/jsonrpc/jsonrpc_gen_test.go | 20 ++++++----- pkg/streamx/provider/jsonrpc/jsonrpc_test.go | 6 ++-- .../provider/jsonrpc/transport_test.go | 2 +- .../provider/ttstream/container/pipe.go | 14 ++++---- .../provider/ttstream/server_provider.go | 6 ++-- .../ttstream/stream_header_trailer.go | 6 ++-- pkg/streamx/provider/ttstream/transport.go | 3 +- .../provider/ttstream/transport_buffer.go | 14 +++++--- .../provider/ttstream/ttstream_client_test.go | 10 +++--- .../provider/ttstream/ttstream_error_test.go | 2 +- .../ttstream/ttstream_gen_service_test.go | 34 ++++++++++++------- .../provider/ttstream/ttstream_server_test.go | 15 +++++--- pkg/streamx/stream.go | 16 +++++---- pkg/streamx/stream_middleware.go | 18 ++++++---- server/streamxserver/server_gen.go | 3 +- server/streamxserver/server_option.go | 6 ++-- 17 files changed, 112 insertions(+), 69 deletions(-) diff --git a/pkg/streamx/header_trailer.go b/pkg/streamx/header_trailer.go index 449bf99847..1c5372a985 100644 --- a/pkg/streamx/header_trailer.go +++ b/pkg/streamx/header_trailer.go @@ -1,4 +1,6 @@ package streamx -type Header map[string]string -type Trailer map[string]string +type ( + Header map[string]string + Trailer map[string]string +) diff --git a/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go b/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go index afae42d52a..7a3730c2e2 100644 --- a/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go +++ b/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go @@ -29,12 +29,14 @@ import ( // === gen code === -type ClientStreamingServer[Req, Res any] streamx.ClientStreamingServer[Req, Res] -type ServerStreamingServer[Res any] streamx.ServerStreamingServer[Res] -type BidiStreamingServer[Req, Res any] streamx.BidiStreamingServer[Req, Res] -type ClientStreamingClient[Req, Res any] streamx.ClientStreamingClient[Req, Res] -type ServerStreamingClient[Res any] streamx.ServerStreamingClient[Res] -type BidiStreamingClient[Req, Res any] streamx.BidiStreamingClient[Req, Res] +type ( + ClientStreamingServer[Req, Res any] streamx.ClientStreamingServer[Req, Res] + ServerStreamingServer[Res any] streamx.ServerStreamingServer[Res] + BidiStreamingServer[Req, Res any] streamx.BidiStreamingServer[Req, Res] + ClientStreamingClient[Req, Res any] streamx.ClientStreamingClient[Req, Res] + ServerStreamingClient[Res any] streamx.ServerStreamingClient[Res] + BidiStreamingClient[Req, Res any] streamx.BidiStreamingClient[Req, Res] +) var serviceInfo = &serviceinfo.ServiceInfo{ ServiceName: "a.b.c", @@ -165,13 +167,15 @@ func (c *kClient) ClientStream(ctx context.Context, callOptions ...streamxcallop } func (c *kClient) ServerStream(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error) { + stream ServerStreamingClient[Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.Client, serviceinfo.StreamingServer, "ServerStream", req, nil, callOptions...) } func (c *kClient) BidiStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error) { + stream BidiStreamingClient[Request, Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.Client, serviceinfo.StreamingBidirectional, "BidiStream", nil, nil, callOptions...) } diff --git a/pkg/streamx/provider/jsonrpc/jsonrpc_test.go b/pkg/streamx/provider/jsonrpc/jsonrpc_test.go index ecfa8c3f6e..4d02753f5a 100644 --- a/pkg/streamx/provider/jsonrpc/jsonrpc_test.go +++ b/pkg/streamx/provider/jsonrpc/jsonrpc_test.go @@ -35,7 +35,7 @@ import ( ) func TestJSONRPC(t *testing.T) { - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, err := netpoll.CreateListener("tcp", addr) test.Assert(t, err == nil, err) @@ -187,8 +187,8 @@ func TestJSONRPC(t *testing.T) { test.Assert(t, err == nil, err) t.Logf("Client ServerStream recv: %v", res) } - //err = ss.CloseSend(ctx) - //test.Assert(t, err == nil, err) + // err = ss.CloseSend(ctx) + // test.Assert(t, err == nil, err) atomic.AddInt32(&serverStreamCount, -1) waitServerStreamDone() diff --git a/pkg/streamx/provider/jsonrpc/transport_test.go b/pkg/streamx/provider/jsonrpc/transport_test.go index 0327eb12f6..187e15e7c8 100644 --- a/pkg/streamx/provider/jsonrpc/transport_test.go +++ b/pkg/streamx/provider/jsonrpc/transport_test.go @@ -68,7 +68,7 @@ func TestTransport(t *testing.T) { Extra: map[string]interface{}{"streaming": true}, } - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, err := net.Listen("tcp", addr) test.Assert(t, err == nil, err) diff --git a/pkg/streamx/provider/ttstream/container/pipe.go b/pkg/streamx/provider/ttstream/container/pipe.go index 6847002003..791670261b 100644 --- a/pkg/streamx/provider/ttstream/container/pipe.go +++ b/pkg/streamx/provider/ttstream/container/pipe.go @@ -32,12 +32,14 @@ const ( pipeStateCanceled pipeState = 3 ) -var ErrPipeEOF = io.EOF -var ErrPipeCanceled = fmt.Errorf("pipe canceled") -var stateErrors map[pipeState]error = map[pipeState]error{ - pipeStateClosed: ErrPipeEOF, - pipeStateCanceled: ErrPipeCanceled, -} +var ( + ErrPipeEOF = io.EOF + ErrPipeCanceled = fmt.Errorf("pipe canceled") + stateErrors map[pipeState]error = map[pipeState]error{ + pipeStateClosed: ErrPipeEOF, + pipeStateCanceled: ErrPipeCanceled, + } +) // Pipe implement a queue that never block on Write but block on Read if there is nothing to read type Pipe[Item any] struct { diff --git a/pkg/streamx/provider/ttstream/server_provider.go b/pkg/streamx/provider/ttstream/server_provider.go index 07d5c0d72f..5b62dea78f 100644 --- a/pkg/streamx/provider/ttstream/server_provider.go +++ b/pkg/streamx/provider/ttstream/server_provider.go @@ -34,8 +34,10 @@ import ( "github.com/cloudwego/kitex/pkg/utils" ) -type serverTransCtxKey struct{} -type serverStreamCancelCtxKey struct{} +type ( + serverTransCtxKey struct{} + serverStreamCancelCtxKey struct{} +) func NewServerProvider(sinfo *serviceinfo.ServiceInfo, opts ...ServerProviderOption) (streamx.ServerProvider, error) { sp := new(serverProvider) diff --git a/pkg/streamx/provider/ttstream/stream_header_trailer.go b/pkg/streamx/provider/ttstream/stream_header_trailer.go index beedb24f41..611c12a0ca 100644 --- a/pkg/streamx/provider/ttstream/stream_header_trailer.go +++ b/pkg/streamx/provider/ttstream/stream_header_trailer.go @@ -22,8 +22,10 @@ import ( "github.com/cloudwego/kitex/pkg/streamx" ) -var _ ClientStreamMeta = (*clientStream)(nil) -var _ ServerStreamMeta = (*serverStream)(nil) +var ( + _ ClientStreamMeta = (*clientStream)(nil) + _ ServerStreamMeta = (*serverStream)(nil) +) func (s *clientStream) Header() (streamx.Header, error) { sig := <-s.headerSig diff --git a/pkg/streamx/provider/ttstream/transport.go b/pkg/streamx/provider/ttstream/transport.go index e7686bfdf3..3506e35b79 100644 --- a/pkg/streamx/provider/ttstream/transport.go +++ b/pkg/streamx/provider/ttstream/transport.go @@ -332,7 +332,8 @@ var clientStreamID int32 // it's typically used by client side // newStreamIO is concurrency safe func (t *transport) newStreamIO( - ctx context.Context, method string, intHeader IntHeader, strHeader streamx.Header) (*streamIO, error) { + ctx context.Context, method string, intHeader IntHeader, strHeader streamx.Header, +) (*streamIO, error) { if t.kind != clientTransport { return nil, fmt.Errorf("transport already be used as other kind") } diff --git a/pkg/streamx/provider/ttstream/transport_buffer.go b/pkg/streamx/provider/ttstream/transport_buffer.go index a51a47c64d..36620fac46 100644 --- a/pkg/streamx/provider/ttstream/transport_buffer.go +++ b/pkg/streamx/provider/ttstream/transport_buffer.go @@ -24,12 +24,16 @@ import ( "github.com/cloudwego/netpoll" ) -var _ bufiox.Reader = (*readerBuffer)(nil) -var _ bufiox.Writer = (*writerBuffer)(nil) -var _ gopkgthrift.NocopyWriter = (*writerBuffer)(nil) +var ( + _ bufiox.Reader = (*readerBuffer)(nil) + _ bufiox.Writer = (*writerBuffer)(nil) + _ gopkgthrift.NocopyWriter = (*writerBuffer)(nil) +) -var readerBufferPool sync.Pool -var writerBufferPool sync.Pool +var ( + readerBufferPool sync.Pool + writerBufferPool sync.Pool +) func newReaderBuffer(reader netpoll.Reader) (rb *readerBuffer) { if v := readerBufferPool.Get(); v != nil { diff --git a/pkg/streamx/provider/ttstream/ttstream_client_test.go b/pkg/streamx/provider/ttstream/ttstream_client_test.go index 0e11434e73..f9c869cc0a 100644 --- a/pkg/streamx/provider/ttstream/ttstream_client_test.go +++ b/pkg/streamx/provider/ttstream/ttstream_client_test.go @@ -64,7 +64,7 @@ func TestMain(m *testing.M) { } func TestTTHeaderStreaming(t *testing.T) { - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, err := netpoll.CreateListener("tcp", addr) test.Assert(t, err == nil, err) defer ln.Close() @@ -367,7 +367,7 @@ func TestTTHeaderStreamingLongConn(t *testing.T) { log.Println(http.ListenAndServe("localhost:6060", nil)) }() - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, _ := netpoll.CreateListener("tcp", addr) defer ln.Close() @@ -462,7 +462,7 @@ func TestTTHeaderStreamingLongConn(t *testing.T) { } func TestTTHeaderStreamingRecvTimeout(t *testing.T) { - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, _ := netpoll.CreateListener("tcp", addr) defer ln.Close() @@ -531,7 +531,7 @@ func TestTTHeaderStreamingRecvTimeout(t *testing.T) { } func TestTTHeaderStreamingServerGoroutines(t *testing.T) { - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, _ := netpoll.CreateListener("tcp", addr) defer ln.Close() @@ -583,7 +583,7 @@ func TestTTHeaderStreamingServerGoroutines(t *testing.T) { func BenchmarkTTHeaderStreaming(b *testing.B) { klog.SetLevel(klog.LevelWarn) - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, _ := netpoll.CreateListener("tcp", addr) defer ln.Close() diff --git a/pkg/streamx/provider/ttstream/ttstream_error_test.go b/pkg/streamx/provider/ttstream/ttstream_error_test.go index 70262208e4..78f9bcb3f0 100644 --- a/pkg/streamx/provider/ttstream/ttstream_error_test.go +++ b/pkg/streamx/provider/ttstream/ttstream_error_test.go @@ -47,7 +47,7 @@ func assertBizErr(t *testing.T, err error) { } func TestTTHeaderStreamingErrorHandling(t *testing.T) { - var addr = test.GetLocalAddress() + addr := test.GetLocalAddress() ln, err := netpoll.CreateListener("tcp", addr) test.Assert(t, err == nil, err) defer ln.Close() diff --git a/pkg/streamx/provider/ttstream/ttstream_gen_service_test.go b/pkg/streamx/provider/ttstream/ttstream_gen_service_test.go index 59062f789f..a7d8572c65 100644 --- a/pkg/streamx/provider/ttstream/ttstream_gen_service_test.go +++ b/pkg/streamx/provider/ttstream/ttstream_gen_service_test.go @@ -32,13 +32,17 @@ import ( // === gen code === // --- Define Header and Trailer type --- -type ClientStreamingServer[Req, Res any] streamx.ClientStreamingServer[Req, Res] -type ServerStreamingServer[Res any] streamx.ServerStreamingServer[Res] -type BidiStreamingServer[Req, Res any] streamx.BidiStreamingServer[Req, Res] +type ( + ClientStreamingServer[Req, Res any] streamx.ClientStreamingServer[Req, Res] + ServerStreamingServer[Res any] streamx.ServerStreamingServer[Res] + BidiStreamingServer[Req, Res any] streamx.BidiStreamingServer[Req, Res] +) -type ClientStreamingClient[Req, Res any] streamx.ClientStreamingClient[Req, Res] -type ServerStreamingClient[Res any] streamx.ServerStreamingClient[Res] -type BidiStreamingClient[Req, Res any] streamx.BidiStreamingClient[Req, Res] +type ( + ClientStreamingClient[Req, Res any] streamx.ClientStreamingClient[Req, Res] + ServerStreamingClient[Res any] streamx.ServerStreamingClient[Res] + BidiStreamingClient[Req, Res any] streamx.BidiStreamingClient[Req, Res] +) // --- Define Service Method handler --- var pingpongServiceInfo = &serviceinfo.ServiceInfo{ @@ -226,8 +230,10 @@ type StreamingClientInterface interface { } // --- Define Client Implementation --- -var _ StreamingClientInterface = (*kClient)(nil) -var _ PingPongClientInterface = (*kClient)(nil) +var ( + _ StreamingClientInterface = (*kClient)(nil) + _ PingPongClientInterface = (*kClient)(nil) +) type kClient struct { caller client.Client @@ -260,13 +266,15 @@ func (c *kClient) ClientStream(ctx context.Context, callOptions ...streamxcallop } func (c *kClient) ServerStream(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error) { + stream ServerStreamingClient[Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingServer, "ServerStream", req, nil, callOptions...) } func (c *kClient) BidiStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error) { + stream BidiStreamingClient[Request, Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingBidirectional, "BidiStream", nil, nil, callOptions...) } @@ -287,13 +295,15 @@ func (c *kClient) ClientStreamWithErr(ctx context.Context, callOptions ...stream } func (c *kClient) ServerStreamWithErr(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error) { + stream ServerStreamingClient[Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingServer, "ServerStreamWithErr", req, nil, callOptions...) } func (c *kClient) BidiStreamWithErr(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error) { + stream BidiStreamingClient[Request, Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingBidirectional, "BidiStreamWithErr", nil, nil, callOptions...) } diff --git a/pkg/streamx/provider/ttstream/ttstream_server_test.go b/pkg/streamx/provider/ttstream/ttstream_server_test.go index a0366af090..7471471967 100644 --- a/pkg/streamx/provider/ttstream/ttstream_server_test.go +++ b/pkg/streamx/provider/ttstream/ttstream_server_test.go @@ -27,8 +27,10 @@ import ( "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream/ktx" ) -type pingpongService struct{} -type streamingService struct{} +type ( + pingpongService struct{} + streamingService struct{} +) const ( headerKey = "header1" @@ -63,7 +65,8 @@ func (si *streamingService) Unary(ctx context.Context, req *Request) (*Response, } func (si *streamingService) ClientStream(ctx context.Context, - stream streamx.ClientStreamingServer[Request, Response]) (*Response, error) { + stream streamx.ClientStreamingServer[Request, Response], +) (*Response, error) { var msg string klog.Infof("Server ClientStream start") defer klog.Infof("Server ClientStream end") @@ -87,7 +90,8 @@ func (si *streamingService) ClientStream(ctx context.Context, } func (si *streamingService) ServerStream(ctx context.Context, req *Request, - stream streamx.ServerStreamingServer[Response]) error { + stream streamx.ServerStreamingServer[Response], +) error { klog.Infof("Server ServerStream: req={%v}", req) if err := si.setHeaderAndTrailer(stream); err != nil { @@ -108,7 +112,8 @@ func (si *streamingService) ServerStream(ctx context.Context, req *Request, } func (si *streamingService) BidiStream(ctx context.Context, - stream streamx.BidiStreamingServer[Request, Response]) error { + stream streamx.BidiStreamingServer[Request, Response], +) error { ktx.RegisterCancelCallback(ctx, func() { klog.Debugf("RegisterCancelCallback work!") }) diff --git a/pkg/streamx/stream.go b/pkg/streamx/stream.go index 42a7b043cd..e478a65024 100644 --- a/pkg/streamx/stream.go +++ b/pkg/streamx/stream.go @@ -22,12 +22,14 @@ import ( "github.com/cloudwego/kitex/pkg/serviceinfo" ) -var _ ServerStreamingClient[int] = (*GenericClientStream[int, int])(nil) -var _ ClientStreamingClient[int, int] = (*GenericClientStream[int, int])(nil) -var _ BidiStreamingClient[int, int] = (*GenericClientStream[int, int])(nil) -var _ ServerStreamingServer[int] = (*GenericServerStream[int, int])(nil) -var _ ClientStreamingServer[int, int] = (*GenericServerStream[int, int])(nil) -var _ BidiStreamingServer[int, int] = (*GenericServerStream[int, int])(nil) +var ( + _ ServerStreamingClient[int] = (*GenericClientStream[int, int])(nil) + _ ClientStreamingClient[int, int] = (*GenericClientStream[int, int])(nil) + _ BidiStreamingClient[int, int] = (*GenericClientStream[int, int])(nil) + _ ServerStreamingServer[int] = (*GenericServerStream[int, int])(nil) + _ ClientStreamingServer[int, int] = (*GenericServerStream[int, int])(nil) + _ BidiStreamingServer[int, int] = (*GenericServerStream[int, int])(nil) +) type StreamingMode = serviceinfo.StreamingMode @@ -136,7 +138,7 @@ type ClientStreamingClient[Req, Res any] interface { type ClientStreamingServer[Req, Res any] interface { Recv(ctx context.Context) (*Req, error) - //SendAndClose(ctx context.Context, res *Res) error + // SendAndClose(ctx context.Context, res *Res) error ServerStream ServerStreamMetadata } diff --git a/pkg/streamx/stream_middleware.go b/pkg/streamx/stream_middleware.go index ed2f8e948b..bce62d65a7 100644 --- a/pkg/streamx/stream_middleware.go +++ b/pkg/streamx/stream_middleware.go @@ -27,14 +27,20 @@ type StreamHandler struct { StreamSendMiddleware StreamSendMiddleware } -type StreamEndpoint func(ctx context.Context, streamArgs StreamArgs, reqArgs StreamReqArgs, resArgs StreamResArgs) (err error) -type StreamMiddleware func(next StreamEndpoint) StreamEndpoint +type ( + StreamEndpoint func(ctx context.Context, streamArgs StreamArgs, reqArgs StreamReqArgs, resArgs StreamResArgs) (err error) + StreamMiddleware func(next StreamEndpoint) StreamEndpoint +) -type StreamRecvEndpoint func(ctx context.Context, stream Stream, res any) (err error) -type StreamSendEndpoint func(ctx context.Context, stream Stream, req any) (err error) +type ( + StreamRecvEndpoint func(ctx context.Context, stream Stream, res any) (err error) + StreamSendEndpoint func(ctx context.Context, stream Stream, req any) (err error) +) -type StreamRecvMiddleware func(next StreamRecvEndpoint) StreamRecvEndpoint -type StreamSendMiddleware func(next StreamSendEndpoint) StreamSendEndpoint +type ( + StreamRecvMiddleware func(next StreamRecvEndpoint) StreamRecvEndpoint + StreamSendMiddleware func(next StreamSendEndpoint) StreamSendEndpoint +) func StreamMiddlewareChain(mws ...StreamMiddleware) StreamMiddleware { return func(next StreamEndpoint) StreamEndpoint { diff --git a/server/streamxserver/server_gen.go b/server/streamxserver/server_gen.go index f9ec27aad2..c417b0cff3 100644 --- a/server/streamxserver/server_gen.go +++ b/server/streamxserver/server_gen.go @@ -14,7 +14,8 @@ var invokerCache sync.Map func InvokeStream[Req, Res any]( ctx context.Context, smode serviceinfo.StreamingMode, - handler any, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { + handler any, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs, +) (err error) { // prepare args sArgs := streamx.GetStreamArgsFromContext(ctx) if sArgs == nil { diff --git a/server/streamxserver/server_option.go b/server/streamxserver/server_option.go index f9233703db..e6e04415b5 100644 --- a/server/streamxserver/server_option.go +++ b/server/streamxserver/server_option.go @@ -8,8 +8,10 @@ import ( "github.com/cloudwego/kitex/server" ) -type Option internal_server.Option -type Options = internal_server.Options +type ( + Option internal_server.Option + Options = internal_server.Options +) func WithListener(ln net.Listener) Option { return ConvertNativeServerOption(server.WithListener(ln)) From 65f303a5d0996158b9d4bf29d283c8c232bab573 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 17:29:17 +0800 Subject: [PATCH 04/13] chore: refactor unit test struct --- .../provider/jsonrpc/jsonrpc_gen_test.go | 181 ----- .../provider/jsonrpc/jsonrpc_impl_test.go | 84 --- pkg/streamx/provider/jsonrpc/jsonrpc_test.go | 231 ------- pkg/streamx/provider/ttstream/transport.go | 1 + .../provider/ttstream/ttstream_client_test.go | 629 ------------------ .../provider/ttstream/ttstream_common_test.go | 61 -- .../provider/ttstream/ttstream_error_test.go | 172 ----- pkg/streamx/streamx_common_test.go | 94 +++ ...odec_test.go => streamx_gen_codec_test.go} | 2 +- ...ce_test.go => streamx_gen_service_test.go} | 55 +- ...r_test.go => streamx_user_service_test.go} | 13 +- pkg/streamx/streamx_user_test.go | 603 +++++++++++++++++ 12 files changed, 734 insertions(+), 1392 deletions(-) delete mode 100644 pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go delete mode 100644 pkg/streamx/provider/jsonrpc/jsonrpc_impl_test.go delete mode 100644 pkg/streamx/provider/jsonrpc/jsonrpc_test.go delete mode 100644 pkg/streamx/provider/ttstream/ttstream_client_test.go delete mode 100644 pkg/streamx/provider/ttstream/ttstream_common_test.go delete mode 100644 pkg/streamx/provider/ttstream/ttstream_error_test.go create mode 100644 pkg/streamx/streamx_common_test.go rename pkg/streamx/{provider/ttstream/ttstream_gen_codec_test.go => streamx_gen_codec_test.go} (99%) rename pkg/streamx/{provider/ttstream/ttstream_gen_service_test.go => streamx_gen_service_test.go} (85%) rename pkg/streamx/{provider/ttstream/ttstream_server_test.go => streamx_user_service_test.go} (93%) create mode 100644 pkg/streamx/streamx_user_test.go diff --git a/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go b/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go deleted file mode 100644 index 7a3730c2e2..0000000000 --- a/pkg/streamx/provider/jsonrpc/jsonrpc_gen_test.go +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2024 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package jsonrpc_test - -import ( - "context" - - "github.com/cloudwego/kitex/client/streamxclient" - "github.com/cloudwego/kitex/client/streamxclient/streamxcallopt" - "github.com/cloudwego/kitex/pkg/serviceinfo" - "github.com/cloudwego/kitex/pkg/streamx" - "github.com/cloudwego/kitex/pkg/streamx/provider/jsonrpc" - "github.com/cloudwego/kitex/server/streamxserver" -) - -// === gen code === - -type ( - ClientStreamingServer[Req, Res any] streamx.ClientStreamingServer[Req, Res] - ServerStreamingServer[Res any] streamx.ServerStreamingServer[Res] - BidiStreamingServer[Req, Res any] streamx.BidiStreamingServer[Req, Res] - ClientStreamingClient[Req, Res any] streamx.ClientStreamingClient[Req, Res] - ServerStreamingClient[Res any] streamx.ServerStreamingClient[Res] - BidiStreamingClient[Req, Res any] streamx.BidiStreamingClient[Req, Res] -) - -var serviceInfo = &serviceinfo.ServiceInfo{ - ServiceName: "a.b.c", - Methods: map[string]serviceinfo.MethodInfo{ - "Unary": serviceinfo.NewMethodInfo( - func(ctx context.Context, handler, reqArgs, resArgs interface{}) error { - return streamxserver.InvokeStream[Request, Response]( - ctx, serviceinfo.StreamingUnary, handler.(streamx.StreamHandler), reqArgs.(streamx.StreamReqArgs), resArgs.(streamx.StreamResArgs)) - }, - nil, - nil, - false, - serviceinfo.WithStreamingMode(serviceinfo.StreamingUnary), - ), - "ClientStream": serviceinfo.NewMethodInfo( - func(ctx context.Context, handler, reqArgs, resArgs interface{}) error { - return streamxserver.InvokeStream[Request, Response]( - ctx, serviceinfo.StreamingClient, handler.(streamx.StreamHandler), reqArgs.(streamx.StreamReqArgs), resArgs.(streamx.StreamResArgs)) - }, - nil, - nil, - false, - serviceinfo.WithStreamingMode(serviceinfo.StreamingClient), - ), - "ServerStream": serviceinfo.NewMethodInfo( - func(ctx context.Context, handler, reqArgs, resArgs interface{}) error { - return streamxserver.InvokeStream[Request, Response]( - ctx, serviceinfo.StreamingServer, handler.(streamx.StreamHandler), reqArgs.(streamx.StreamReqArgs), resArgs.(streamx.StreamResArgs)) - }, - nil, - nil, - false, - serviceinfo.WithStreamingMode(serviceinfo.StreamingServer), - ), - "BidiStream": serviceinfo.NewMethodInfo( - func(ctx context.Context, handler, reqArgs, resArgs interface{}) error { - return streamxserver.InvokeStream[Request, Response]( - ctx, serviceinfo.StreamingBidirectional, handler.(streamx.StreamHandler), reqArgs.(streamx.StreamReqArgs), resArgs.(streamx.StreamResArgs)) - }, - nil, - nil, - false, - serviceinfo.WithStreamingMode(serviceinfo.StreamingBidirectional), - ), - }, - Extra: map[string]interface{}{"streaming": true, "streamx": true}, -} - -func NewClient(destService string, opts ...streamxclient.Option) (ClientInterface, error) { - var options []streamxclient.Option - options = append(options, streamxclient.WithDestService(destService)) - options = append(options, opts...) - cp, err := jsonrpc.NewClientProvider(serviceInfo) - if err != nil { - return nil, err - } - options = append(options, streamxclient.WithProvider(cp)) - cli, err := streamxclient.NewClient(serviceInfo, options...) - if err != nil { - return nil, err - } - kc := &kClient{Client: cli} - return kc, nil -} - -func NewServer(handler ServerInterface, opts ...streamxserver.Option) (streamxserver.Server, error) { - var options []streamxserver.Option - options = append(options, opts...) - sp, err := jsonrpc.NewServerProvider(serviceInfo) - if err != nil { - return nil, err - } - svr := streamxserver.NewServer(options...) - if err := svr.RegisterService(serviceInfo, handler, streamxserver.WithProvider(sp)); err != nil { - return nil, err - } - return svr, nil -} - -type Request struct { - Type int32 `json:"Type"` - Message string `json:"Message"` -} - -type Response struct { - Type int32 `json:"Type"` - Message string `json:"Message"` -} - -type ServerInterface interface { - Unary(ctx context.Context, req *Request) (*Response, error) - ClientStream(ctx context.Context, stream ClientStreamingServer[Request, Response]) (*Response, error) - ServerStream(ctx context.Context, req *Request, stream ServerStreamingServer[Response]) error - BidiStream(ctx context.Context, stream BidiStreamingServer[Request, Response]) error -} - -type ClientInterface interface { - Unary(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) (r *Response, err error) - ClientStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream ClientStreamingClient[Request, Response], err error) - ServerStream(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error) - BidiStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error) -} - -// --- Define Client Implementation --- - -var _ ClientInterface = (*kClient)(nil) - -type kClient struct { - streamxclient.Client -} - -func (c *kClient) Unary(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) (*Response, error) { - res := new(Response) - _, err := streamxclient.InvokeStream[Request, Response]( - ctx, c.Client, serviceinfo.StreamingUnary, "Unary", req, res, callOptions...) - if err != nil { - return nil, err - } - return res, nil -} - -func (c *kClient) ClientStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) (stream ClientStreamingClient[Request, Response], err error) { - return streamxclient.InvokeStream[Request, Response]( - ctx, c.Client, serviceinfo.StreamingClient, "ClientStream", nil, nil, callOptions...) -} - -func (c *kClient) ServerStream(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error, -) { - return streamxclient.InvokeStream[Request, Response]( - ctx, c.Client, serviceinfo.StreamingServer, "ServerStream", req, nil, callOptions...) -} - -func (c *kClient) BidiStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error, -) { - return streamxclient.InvokeStream[Request, Response]( - ctx, c.Client, serviceinfo.StreamingBidirectional, "BidiStream", nil, nil, callOptions...) -} diff --git a/pkg/streamx/provider/jsonrpc/jsonrpc_impl_test.go b/pkg/streamx/provider/jsonrpc/jsonrpc_impl_test.go deleted file mode 100644 index c3ba1b7644..0000000000 --- a/pkg/streamx/provider/jsonrpc/jsonrpc_impl_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2024 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package jsonrpc_test - -import ( - "context" - "io" - "log" -) - -type serviceImpl struct{} - -func (si *serviceImpl) Unary(ctx context.Context, req *Request) (*Response, error) { - resp := &Response{Message: req.Message} - log.Printf("Server Unary: req={%v} resp={%v}", req, resp) - return resp, nil -} - -func (si *serviceImpl) ClientStream(ctx context.Context, stream ClientStreamingServer[Request, Response]) (res *Response, err error) { - var msg string - defer log.Printf("Server ClientStream end") - for { - req, err := stream.Recv(ctx) - if err == io.EOF { - res = new(Response) - res.Message = msg - return res, nil - } - if err != nil { - return nil, err - } - msg = req.Message - log.Printf("Server ClientStream: req={%v}", req) - } -} - -func (si *serviceImpl) ServerStream(ctx context.Context, req *Request, stream ServerStreamingServer[Response]) error { - log.Printf("Server ServerStream: req={%v}", req) - for i := 0; i < 3; i++ { - resp := new(Response) - resp.Type = int32(i) - resp.Message = req.Message - err := stream.Send(ctx, resp) - if err != nil { - return err - } - log.Printf("Server ServerStream: resp={%v}", resp) - } - return nil -} - -func (si *serviceImpl) BidiStream(ctx context.Context, stream BidiStreamingServer[Request, Response]) error { - for { - req, err := stream.Recv(ctx) - if err == io.EOF { - return nil - } - if err != nil { - return err - } - - resp := new(Response) - resp.Message = req.Message - err = stream.Send(ctx, resp) - if err != nil { - return err - } - log.Printf("Server BidiStream: req={%v} resp={%v}", req, resp) - } -} diff --git a/pkg/streamx/provider/jsonrpc/jsonrpc_test.go b/pkg/streamx/provider/jsonrpc/jsonrpc_test.go deleted file mode 100644 index 4d02753f5a..0000000000 --- a/pkg/streamx/provider/jsonrpc/jsonrpc_test.go +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2024 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package jsonrpc_test - -import ( - "context" - "errors" - "io" - "log" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/cloudwego/kitex/client/streamxclient" - "github.com/cloudwego/kitex/internal/test" - "github.com/cloudwego/kitex/pkg/streamx" - "github.com/cloudwego/kitex/pkg/streamx/provider/jsonrpc" - "github.com/cloudwego/kitex/server/streamxserver" - "github.com/cloudwego/netpoll" -) - -func TestJSONRPC(t *testing.T) { - addr := test.GetLocalAddress() - ln, err := netpoll.CreateListener("tcp", addr) - test.Assert(t, err == nil, err) - - // create server - var serverStreamCount int32 - waitServerStreamDone := func() { - for atomic.LoadInt32(&serverStreamCount) != 0 { - t.Logf("waitServerStreamDone: %d", atomic.LoadInt32(&serverStreamCount)) - time.Sleep(time.Millisecond * 100) - } - } - methodCount := map[string]int{} - sp, err := jsonrpc.NewServerProvider(serviceInfo) - test.Assert(t, err == nil, err) - svr := streamxserver.NewServer(streamxserver.WithListener(ln)) - err = svr.RegisterService(serviceInfo, new(serviceImpl), - streamxserver.WithProvider(sp), - streamxserver.WithStreamMiddleware( - // middleware example: server streaming mode - func(next streamx.StreamEndpoint) streamx.StreamEndpoint { - return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { - log.Printf("Server middleware before next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs) - test.Assert(t, streamArgs.Stream() != nil) - - switch streamArgs.Stream().Mode() { - case streamx.StreamingUnary: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() != nil) - case streamx.StreamingClient: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() != nil) - case streamx.StreamingServer: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - case streamx.StreamingBidirectional: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - } - test.Assert(t, err == nil, err) - methodCount[streamArgs.Stream().Method()]++ - - log.Printf("Server middleware after next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs.Stream()) - atomic.AddInt32(&serverStreamCount, 1) - return nil - } - }, - ), - ) - test.Assert(t, err == nil, err) - go func() { - err := svr.Run() - test.Assert(t, err == nil, err) - }() - defer svr.Stop() - time.Sleep(time.Millisecond * 100) - - // create client - ctx := context.Background() - cli, err := NewClient( - "a.b.c", - streamxclient.WithHostPorts(addr), - streamxclient.WithStreamRecvMiddleware(func(next streamx.StreamRecvEndpoint) streamx.StreamRecvEndpoint { - return func(ctx context.Context, stream streamx.Stream, res any) (err error) { - return next(ctx, stream, res) - } - }), - streamxclient.WithStreamMiddleware(func(next streamx.StreamEndpoint) streamx.StreamEndpoint { - return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { - log.Printf("Client middleware before next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs.Stream()) - err = next(ctx, streamArgs, reqArgs, resArgs) - log.Printf("Client middleware after next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs.Stream()) - - test.Assert(t, streamArgs.Stream() != nil) - switch streamArgs.Stream().Mode() { - case streamx.StreamingUnary: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() != nil) - case streamx.StreamingClient: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - case streamx.StreamingServer: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - case streamx.StreamingBidirectional: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - } - test.Assert(t, err == nil, err) - return err - } - }), - ) - test.Assert(t, err == nil, err) - - t.Logf("=== Unary ===") - req := new(Request) - req.Message = "Unary" - res, err := cli.Unary(ctx, req) - test.Assert(t, err == nil, err) - test.Assert(t, req.Message == res.Message, res.Message) - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() - - // client stream - t.Logf("=== ClientStream ===") - cs, err := cli.ClientStream(ctx) - test.Assert(t, err == nil, err) - for i := 0; i < 3; i++ { - req := new(Request) - req.Type = int32(i) - req.Message = "ClientStream" - err = cs.Send(ctx, req) - test.Assert(t, err == nil, err) - } - res, err = cs.CloseAndRecv(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, res.Message == "ClientStream", res.Message) - t.Logf("Client ClientStream CloseAndRecv: %v", res) - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() - - // server stream - t.Logf("=== ServerStream ===") - req = new(Request) - req.Message = "ServerStream" - ss, err := cli.ServerStream(ctx, req) - test.Assert(t, err == nil, err) - for { - res, err := ss.Recv(ctx) - if errors.Is(err, io.EOF) { - break - } - test.Assert(t, err == nil, err) - t.Logf("Client ServerStream recv: %v", res) - } - // err = ss.CloseSend(ctx) - // test.Assert(t, err == nil, err) - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() - - // bidi stream - t.Logf("=== BidiStream ===") - bs, err := cli.BidiStream(ctx) - test.Assert(t, err == nil, err) - round := 5 - msg := "BidiStream" - var wg sync.WaitGroup - wg.Add(2) - go func() { - defer wg.Done() - for i := 0; i < round; i++ { - req := new(Request) - req.Message = msg - err := bs.Send(ctx, req) - test.Assert(t, err == nil, err) - } - err = bs.CloseSend(ctx) - test.Assert(t, err == nil, err) - }() - go func() { - defer wg.Done() - i := 0 - for { - res, err := bs.Recv(ctx) - if errors.Is(err, io.EOF) { - break - } - i++ - test.Assert(t, err == nil, err) - test.Assert(t, msg == res.Message, res.Message) - } - test.Assert(t, i == round, i) - }() - wg.Wait() - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() -} diff --git a/pkg/streamx/provider/ttstream/transport.go b/pkg/streamx/provider/ttstream/transport.go index 3506e35b79..dc97d62f09 100644 --- a/pkg/streamx/provider/ttstream/transport.go +++ b/pkg/streamx/provider/ttstream/transport.go @@ -222,6 +222,7 @@ func (t *transport) loopWrite() error { } for i := 0; i < n; i++ { fr := fcache[i] + klog.Debugf("transport[%d] EncodeFrame: fr=%v", t.kind, fr) if err = EncodeFrame(context.Background(), writer, fr); err != nil { return err } diff --git a/pkg/streamx/provider/ttstream/ttstream_client_test.go b/pkg/streamx/provider/ttstream/ttstream_client_test.go deleted file mode 100644 index f9c869cc0a..0000000000 --- a/pkg/streamx/provider/ttstream/ttstream_client_test.go +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright 2024 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ttstream_test - -import ( - "context" - "errors" - "io" - "log" - "net/http" - _ "net/http/pprof" - "runtime" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/cloudwego/netpoll" - - "github.com/cloudwego/kitex/client" - "github.com/cloudwego/kitex/client/streamxclient" - "github.com/cloudwego/kitex/internal/test" - "github.com/cloudwego/kitex/pkg/klog" - "github.com/cloudwego/kitex/pkg/remote/codec/thrift" - "github.com/cloudwego/kitex/pkg/streamx" - "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream" - "github.com/cloudwego/kitex/server" - "github.com/cloudwego/kitex/server/streamxserver" - "github.com/cloudwego/kitex/transport" -) - -func init() { - klog.SetLevel(klog.LevelDebug) -} - -func testHeaderAndTrailer(t *testing.T, stream streamx.ClientStreamMetadata) { - hd, err := stream.Header() - test.Assert(t, err == nil, err) - test.Assert(t, hd[headerKey] == headerVal, hd) - tl, err := stream.Trailer() - test.Assert(t, err == nil, err) - test.Assert(t, tl[trailerKey] == trailerVal, tl) -} - -func TestMain(m *testing.M) { - go func() { - log.Println(http.ListenAndServe("localhost:6060", nil)) - }() - m.Run() -} - -func TestTTHeaderStreaming(t *testing.T) { - addr := test.GetLocalAddress() - ln, err := netpoll.CreateListener("tcp", addr) - test.Assert(t, err == nil, err) - defer ln.Close() - - // create server - var serverStreamCount int32 - waitServerStreamDone := func() { - for atomic.LoadInt32(&serverStreamCount) != 0 { - t.Logf("waitServerStreamDone: %d", atomic.LoadInt32(&serverStreamCount)) - time.Sleep(time.Millisecond * 100) - } - } - var serverRecvCount int32 - var serverSendCount int32 - svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) - // register pingpong service - err = svr.RegisterService(pingpongServiceInfo, new(pingpongService)) - test.Assert(t, err == nil, err) - // register streamingService as ttstreaam provider - sp, err := ttstream.NewServerProvider(streamingServiceInfo) - test.Assert(t, err == nil, err) - err = svr.RegisterService( - streamingServiceInfo, - new(streamingService), - streamxserver.WithProvider(sp), - streamxserver.WithStreamRecvMiddleware(func(next streamx.StreamRecvEndpoint) streamx.StreamRecvEndpoint { - return func(ctx context.Context, stream streamx.Stream, res any) (err error) { - err = next(ctx, stream, res) - if err == nil { - atomic.AddInt32(&serverRecvCount, 1) - } else { - log.Printf("server recv middleware err=%v", err) - } - return err - } - }), - streamxserver.WithStreamSendMiddleware(func(next streamx.StreamSendEndpoint) streamx.StreamSendEndpoint { - return func(ctx context.Context, stream streamx.Stream, req any) (err error) { - err = next(ctx, stream, req) - if err == nil { - atomic.AddInt32(&serverSendCount, 1) - } else { - log.Printf("server send middleware err=%v", err) - } - return err - } - }), - streamxserver.WithStreamMiddleware( - // middleware example: server streaming mode - func(next streamx.StreamEndpoint) streamx.StreamEndpoint { - return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { - log.Printf("Server middleware before next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs) - test.Assert(t, streamArgs.Stream() != nil) - test.Assert(t, ValidateMetadata(ctx)) - - log.Printf("Server handler start") - switch streamArgs.Stream().Mode() { - case streamx.StreamingUnary: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() != nil) - case streamx.StreamingClient: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() != nil) - case streamx.StreamingServer: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - case streamx.StreamingBidirectional: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - } - test.Assert(t, err == nil, err) - log.Printf("Server handler end") - - log.Printf("Server middleware after next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs.Stream()) - atomic.AddInt32(&serverStreamCount, 1) - return nil - } - }, - ), - ) - test.Assert(t, err == nil, err) - go func() { - err := svr.Run() - test.Assert(t, err == nil, err) - }() - defer svr.Stop() - test.WaitServerStart(addr) - - // create client - pingpongClient, err := NewPingPongClient( - "kitex.service.pingpong", - client.WithHostPorts(addr), - client.WithTransportProtocol(transport.TTHeaderFramed), - client.WithPayloadCodec(thrift.NewThriftCodecWithConfig(thrift.FastRead|thrift.FastWrite|thrift.EnableSkipDecoder)), - ) - test.Assert(t, err == nil, err) - // create streaming client - cp, _ := ttstream.NewClientProvider( - streamingServiceInfo, - ttstream.WithClientLongConnPool(ttstream.DefaultLongConnConfig), - ) - streamClient, err := NewStreamingClient( - "kitex.service.streaming", - streamxclient.WithProvider(cp), - streamxclient.WithHostPorts(addr), - streamxclient.WithStreamRecvMiddleware(func(next streamx.StreamRecvEndpoint) streamx.StreamRecvEndpoint { - return func(ctx context.Context, stream streamx.Stream, res any) (err error) { - err = next(ctx, stream, res) - log.Printf("Client recv middleware %v", res) - return err - } - }), - streamxclient.WithStreamSendMiddleware(func(next streamx.StreamSendEndpoint) streamx.StreamSendEndpoint { - return func(ctx context.Context, stream streamx.Stream, req any) (err error) { - err = next(ctx, stream, req) - log.Printf("Client send middleware %v", req) - return err - } - }), - streamxclient.WithStreamMiddleware(func(next streamx.StreamEndpoint) streamx.StreamEndpoint { - return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { - // validate ctx - test.Assert(t, ValidateMetadata(ctx)) - - log.Printf("Client middleware before next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs.Stream()) - err = next(ctx, streamArgs, reqArgs, resArgs) - test.Assert(t, err == nil, err) - log.Printf("Client middleware after next: reqArgs=%v resArgs=%v streamArgs=%v", - reqArgs.Req(), resArgs.Res(), streamArgs.Stream()) - - test.Assert(t, streamArgs.Stream() != nil) - switch streamArgs.Stream().Mode() { - case streamx.StreamingUnary: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() != nil) - case streamx.StreamingClient: - test.Assert(t, reqArgs.Req() == nil, reqArgs.Req()) - test.Assert(t, resArgs.Res() == nil) - case streamx.StreamingServer: - test.Assert(t, reqArgs.Req() != nil) - test.Assert(t, resArgs.Res() == nil) - case streamx.StreamingBidirectional: - test.Assert(t, reqArgs.Req() == nil) - test.Assert(t, resArgs.Res() == nil) - } - return err - } - }), - ) - test.Assert(t, err == nil, err) - - // prepare metainfo - ctx := context.Background() - ctx = SetMetadata(ctx) - - t.Logf("=== PingPong ===") - req := new(Request) - req.Message = "PingPong" - res, err := pingpongClient.PingPong(ctx, req) - test.Assert(t, err == nil, err) - test.Assert(t, req.Message == res.Message, res) - - t.Logf("=== Unary ===") - req = new(Request) - req.Type = 10000 - req.Message = "Unary" - res, err = streamClient.Unary(ctx, req) - test.Assert(t, err == nil, err) - test.Assert(t, req.Type == res.Type, res.Type) - test.Assert(t, req.Message == res.Message, res.Message) - test.Assert(t, serverRecvCount == 1, serverRecvCount) - test.Assert(t, serverSendCount == 1, serverSendCount) - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() - serverRecvCount = 0 - serverSendCount = 0 - - // client stream - round := 5 - t.Logf("=== ClientStream ===") - cs, err := streamClient.ClientStream(ctx) - test.Assert(t, err == nil, err) - for i := 0; i < round; i++ { - req := new(Request) - req.Type = int32(i) - req.Message = "ClientStream" - err = cs.Send(ctx, req) - test.Assert(t, err == nil, err) - } - res, err = cs.CloseAndRecv(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, res.Message == "ClientStream", res.Message) - t.Logf("Client ClientStream CloseAndRecv: %v", res) - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() - test.DeepEqual(t, serverRecvCount, int32(round)) - test.Assert(t, serverSendCount == 1, serverSendCount) - testHeaderAndTrailer(t, cs) - cs = nil - serverRecvCount = 0 - serverSendCount = 0 - runtime.GC() - - // server stream - t.Logf("=== ServerStream ===") - req = new(Request) - req.Message = "ServerStream" - ss, err := streamClient.ServerStream(ctx, req) - test.Assert(t, err == nil, err) - received := 0 - for { - res, err := ss.Recv(ctx) - if errors.Is(err, io.EOF) { - break - } - test.Assert(t, err == nil, err) - received++ - t.Logf("Client ServerStream recv: %v", res) - } - err = ss.CloseSend(ctx) - test.Assert(t, err == nil, err) - atomic.AddInt32(&serverStreamCount, -1) - waitServerStreamDone() - test.Assert(t, serverRecvCount == 1, serverRecvCount) - test.Assert(t, serverSendCount == int32(received), serverSendCount, received) - testHeaderAndTrailer(t, ss) - ss = nil - serverRecvCount = 0 - serverSendCount = 0 - runtime.GC() - - // bidi stream - t.Logf("=== BidiStream ===") - concurrent := 1 - round = 5 - for c := 0; c < concurrent; c++ { - atomic.AddInt32(&serverStreamCount, -1) - go func() { - bs, err := streamClient.BidiStream(ctx) - test.Assert(t, err == nil, err) - msg := "BidiStream" - var wg sync.WaitGroup - wg.Add(2) - go func() { - defer wg.Done() - for i := 0; i < round; i++ { - req := new(Request) - req.Message = msg - err := bs.Send(ctx, req) - test.Assert(t, err == nil, err) - } - err = bs.CloseSend(ctx) - test.Assert(t, err == nil, err) - }() - go func() { - defer wg.Done() - i := 0 - for { - res, err := bs.Recv(ctx) - t.Log(res, err) - if errors.Is(err, io.EOF) { - break - } - i++ - test.Assert(t, err == nil, err) - test.Assert(t, msg == res.Message, res.Message) - } - test.Assert(t, i == round, i) - }() - testHeaderAndTrailer(t, bs) - }() - } - waitServerStreamDone() - test.Assert(t, serverRecvCount == int32(concurrent*round), serverRecvCount) - test.Assert(t, serverSendCount == int32(concurrent*round), serverSendCount) - serverRecvCount = 0 - serverSendCount = 0 - runtime.GC() - - streamClient = nil -} - -func TestTTHeaderStreamingLongConn(t *testing.T) { - go func() { - log.Println(http.ListenAndServe("localhost:6060", nil)) - }() - - addr := test.GetLocalAddress() - ln, _ := netpoll.CreateListener("tcp", addr) - defer ln.Close() - - // create server - svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) - // register streamingService as ttstreaam provider - sp, _ := ttstream.NewServerProvider(streamingServiceInfo) - _ = svr.RegisterService( - streamingServiceInfo, - new(streamingService), - streamxserver.WithProvider(sp), - ) - go func() { - _ = svr.Run() - }() - defer svr.Stop() - test.WaitServerStart(addr) - - numGoroutine := runtime.NumGoroutine() - cp, _ := ttstream.NewClientProvider( - streamingServiceInfo, - ttstream.WithClientLongConnPool( - ttstream.LongConnConfig{MaxIdleTimeout: time.Second}, - ), - ) - streamClient, _ := NewStreamingClient( - "kitex.service.streaming", - streamxclient.WithHostPorts(addr), - streamxclient.WithProvider(cp), - ) - ctx := context.Background() - msg := "BidiStream" - - t.Logf("checking only one connection be reused") - var wg sync.WaitGroup - for i := 0; i < 12; i++ { - wg.Add(1) - bs, err := streamClient.BidiStream(ctx) - test.Assert(t, err == nil, err) - req := new(Request) - req.Message = string(make([]byte, 1024)) - err = bs.Send(ctx, req) - test.Assert(t, err == nil, err) - res, err := bs.Recv(ctx) - test.Assert(t, err == nil, err) - err = bs.CloseSend(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, res.Message == req.Message, res.Message) - runtime.SetFinalizer(bs, func(_ any) { - wg.Done() - t.Logf("stream is finalized") - }) - bs = nil - runtime.GC() - wg.Wait() - } - - t.Logf("checking goroutines destroy") - // checking streaming goroutines - streams := 500 - for i := 0; i < streams; i++ { - wg.Add(1) - go func() { - bs, err := streamClient.BidiStream(ctx) - test.Assert(t, err == nil, err) - req := new(Request) - req.Message = msg - err = bs.Send(ctx, req) - test.Assert(t, err == nil, err) - go func() { - defer wg.Done() - res, err := bs.Recv(ctx) - test.Assert(t, err == nil, err) - err = bs.CloseSend(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, res.Message == msg, res.Message) - - testHeaderAndTrailer(t, bs) - }() - }() - } - wg.Wait() - for { - ng := runtime.NumGoroutine() - if ng-numGoroutine < 10 { - break - } - runtime.GC() - time.Sleep(time.Second) - t.Logf("current goroutines=%d, before =%d", ng, numGoroutine) - } -} - -func TestTTHeaderStreamingRecvTimeout(t *testing.T) { - addr := test.GetLocalAddress() - ln, _ := netpoll.CreateListener("tcp", addr) - defer ln.Close() - - // create server - svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) - // register streamingService as ttstreaam provider - sp, _ := ttstream.NewServerProvider(streamingServiceInfo) - _ = svr.RegisterService( - streamingServiceInfo, - new(streamingService), - streamxserver.WithProvider(sp), - ) - go func() { - _ = svr.Run() - }() - defer svr.Stop() - test.WaitServerStart(addr) - - cp, _ := ttstream.NewClientProvider( - streamingServiceInfo, - ttstream.WithClientLongConnPool( - ttstream.LongConnConfig{MaxIdleTimeout: time.Second}, - ), - ) - - // timeout by ctx itself - streamClient, _ := NewStreamingClient( - "kitex.service.streaming", - streamxclient.WithHostPorts(addr), - streamxclient.WithProvider(cp), - ) - ctx := context.Background() - bs, err := streamClient.BidiStream(ctx) - test.Assert(t, err == nil, err) - req := new(Request) - req.Message = string(make([]byte, 1024)) - err = bs.Send(ctx, req) - test.Assert(t, err == nil, err) - ctx, cancel := context.WithCancel(ctx) - cancel() - _, err = bs.Recv(ctx) - test.Assert(t, err != nil, err) - t.Logf("recv timeout error: %v", err) - err = bs.CloseSend(ctx) - test.Assert(t, err == nil, err) - - // timeout by client WithRecvTimeout - streamClient, _ = NewStreamingClient( - "kitex.service.streaming", - streamxclient.WithHostPorts(addr), - streamxclient.WithProvider(cp), - streamxclient.WithRecvTimeout(time.Nanosecond), - ) - ctx = context.Background() - bs, err = streamClient.BidiStream(ctx) - test.Assert(t, err == nil, err) - req = new(Request) - req.Message = string(make([]byte, 1024)) - err = bs.Send(ctx, req) - test.Assert(t, err == nil, err) - _, err = bs.Recv(ctx) - test.Assert(t, err != nil, err) - t.Logf("recv timeout error: %v", err) - err = bs.CloseSend(ctx) - test.Assert(t, err == nil, err) -} - -func TestTTHeaderStreamingServerGoroutines(t *testing.T) { - addr := test.GetLocalAddress() - ln, _ := netpoll.CreateListener("tcp", addr) - defer ln.Close() - - // create server - svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) - // register streamingService as ttstreaam provider - sp, _ := ttstream.NewServerProvider(streamingServiceInfo) - _ = svr.RegisterService( - streamingServiceInfo, - new(streamingService), - streamxserver.WithProvider(sp), - ) - go func() { - _ = svr.Run() - }() - defer svr.Stop() - test.WaitServerStart(addr) - - cp, _ := ttstream.NewClientProvider( - streamingServiceInfo, - ttstream.WithClientLongConnPool(ttstream.LongConnConfig{MaxIdleTimeout: time.Second}), - ) - streamClient, _ := NewStreamingClient( - "kitex.service.streaming", - streamxclient.WithHostPorts(addr), - streamxclient.WithProvider(cp), - ) - - oldNGs := runtime.NumGoroutine() - streams := 100 - streamList := make([]streamx.ServerStream, streams) - for i := 0; i < streams; i++ { - ctx := context.Background() - bs, err := streamClient.BidiStream(ctx) - test.Assert(t, err == nil, err) - streamList[i] = bs - } - ngs := runtime.NumGoroutine() - test.Assert(t, ngs > streams, ngs) - for i := 0; i < streams; i++ { - streamList[i] = nil - } - for ngs-oldNGs > 10 { - runtime.GC() - ngs = runtime.NumGoroutine() - time.Sleep(time.Millisecond * 100) - } -} - -func BenchmarkTTHeaderStreaming(b *testing.B) { - klog.SetLevel(klog.LevelWarn) - addr := test.GetLocalAddress() - ln, _ := netpoll.CreateListener("tcp", addr) - defer ln.Close() - - // create server - svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) - // register streamingService as ttstreaam provider - sp, _ := ttstream.NewServerProvider(streamingServiceInfo) - _ = svr.RegisterService(streamingServiceInfo, new(streamingService), streamxserver.WithProvider(sp)) - go func() { - _ = svr.Run() - }() - defer svr.Stop() - test.WaitServerStart(addr) - - streamClient, _ := NewStreamingClient("kitex.service.streaming", streamxclient.WithHostPorts(addr)) - ctx := context.Background() - bs, err := streamClient.BidiStream(ctx) - if err != nil { - b.Fatal(err) - } - msg := "BidiStream" - var wg sync.WaitGroup - wg.Add(1) - b.ResetTimer() - b.ReportAllocs() - for i := 0; i < b.N; i++ { - req := new(Request) - req.Message = msg - err := bs.Send(ctx, req) - if err != nil { - b.Fatal(err) - } - res, err := bs.Recv(ctx) - if errors.Is(err, io.EOF) { - break - } - _ = res - } - err = bs.CloseSend(ctx) - if err != nil { - b.Fatal(err) - } -} diff --git a/pkg/streamx/provider/ttstream/ttstream_common_test.go b/pkg/streamx/provider/ttstream/ttstream_common_test.go deleted file mode 100644 index 242a75cd10..0000000000 --- a/pkg/streamx/provider/ttstream/ttstream_common_test.go +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2024 CloudWeGo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package ttstream_test - -import ( - "context" - - "github.com/bytedance/gopkg/cloud/metainfo" -) - -var persistKVs = map[string]string{ - "p1": "v1", - "p2": "v2", - "p3": "v3", -} - -var transitKVs = map[string]string{ - "t1": "v1", - "t2": "v2", - "t3": "v3", -} - -func SetMetadata(ctx context.Context) context.Context { - for k, v := range persistKVs { - ctx = metainfo.WithPersistentValue(ctx, k, v) - } - for k, v := range transitKVs { - ctx = metainfo.WithValue(ctx, k, v) - } - return ctx -} - -func ValidateMetadata(ctx context.Context) bool { - for k, v := range persistKVs { - _v, _ := metainfo.GetPersistentValue(ctx, k) - if _v != v { - return false - } - } - for k, v := range transitKVs { - _v, _ := metainfo.GetValue(ctx, k) - if _v != v { - return false - } - } - return true -} diff --git a/pkg/streamx/provider/ttstream/ttstream_error_test.go b/pkg/streamx/provider/ttstream/ttstream_error_test.go deleted file mode 100644 index 78f9bcb3f0..0000000000 --- a/pkg/streamx/provider/ttstream/ttstream_error_test.go +++ /dev/null @@ -1,172 +0,0 @@ -package ttstream_test - -import ( - "context" - "testing" - "time" - - "github.com/cloudwego/gopkg/protocol/thrift" - "github.com/cloudwego/netpoll" - - "github.com/cloudwego/kitex/client/streamxclient" - "github.com/cloudwego/kitex/internal/test" - "github.com/cloudwego/kitex/pkg/kerrors" - "github.com/cloudwego/kitex/pkg/remote" - "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream" - "github.com/cloudwego/kitex/server" - "github.com/cloudwego/kitex/server/streamxserver" -) - -const ( - normalErr int32 = iota + 1 - bizErr -) - -var ( - testCode = int32(10001) - testMsg = "biz testMsg" - testExtra = map[string]string{ - "testKey": "testVal", - } - normalErrMsg = "normal error" -) - -func assertNormalErr(t *testing.T, err error) { - ex, ok := err.(*thrift.ApplicationException) - test.Assert(t, ok, err) - test.Assert(t, ex.TypeID() == remote.InternalError, ex.TypeID()) - test.Assert(t, ex.Msg() == "biz error: "+normalErrMsg, ex.Msg()) -} - -func assertBizErr(t *testing.T, err error) { - bizIntf, ok := kerrors.FromBizStatusError(err) - test.Assert(t, ok) - test.Assert(t, bizIntf.BizStatusCode() == testCode, bizIntf.BizStatusCode()) - test.Assert(t, bizIntf.BizMessage() == testMsg, bizIntf.BizMessage()) - test.DeepEqual(t, bizIntf.BizExtra(), testExtra) -} - -func TestTTHeaderStreamingErrorHandling(t *testing.T) { - addr := test.GetLocalAddress() - ln, err := netpoll.CreateListener("tcp", addr) - test.Assert(t, err == nil, err) - defer ln.Close() - - svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) - sp, err := ttstream.NewServerProvider(streamingServiceInfo) - test.Assert(t, err == nil, err) - err = svr.RegisterService( - streamingServiceInfo, - new(streamingService), - streamxserver.WithProvider(sp), - ) - test.Assert(t, err == nil, err) - go func() { - err := svr.Run() - test.Assert(t, err == nil, err) - }() - defer svr.Stop() - test.WaitServerStart(addr) - - streamClient, err := NewStreamingClient( - "kitex.service.streaming", - streamxclient.WithHostPorts(addr), - ) - test.Assert(t, err == nil, err) - - t.Logf("=== UnaryWithErr normalErr ===") - req := new(Request) - req.Type = normalErr - res, err := streamClient.UnaryWithErr(context.Background(), req) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertNormalErr(t, err) - - t.Logf("=== UnaryWithErr bizErr ===") - req = new(Request) - req.Type = bizErr - res, err = streamClient.UnaryWithErr(context.Background(), req) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertBizErr(t, err) - - t.Logf("=== ClientStreamWithErr normalErr ===") - ctx := context.Background() - cliStream, err := streamClient.ClientStreamWithErr(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, cliStream != nil, cliStream) - req = new(Request) - req.Type = normalErr - err = cliStream.Send(ctx, req) - test.Assert(t, err == nil, err) - res, err = cliStream.CloseAndRecv(ctx) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertNormalErr(t, err) - - t.Logf("=== ClientStreamWithErr bizErr ===") - ctx = context.Background() - cliStream, err = streamClient.ClientStreamWithErr(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, cliStream != nil, cliStream) - req = new(Request) - req.Type = bizErr - err = cliStream.Send(ctx, req) - test.Assert(t, err == nil, err) - res, err = cliStream.CloseAndRecv(ctx) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertBizErr(t, err) - - t.Logf("=== ServerStreamWithErr normalErr ===") - ctx = context.Background() - req = new(Request) - req.Type = normalErr - svrStream, err := streamClient.ServerStreamWithErr(ctx, req) - test.Assert(t, err == nil, err) - test.Assert(t, svrStream != nil, svrStream) - res, err = svrStream.Recv(ctx) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertNormalErr(t, err) - - t.Logf("=== ServerStreamWithErr bizErr ===") - ctx = context.Background() - req = new(Request) - req.Type = bizErr - svrStream, err = streamClient.ServerStreamWithErr(ctx, req) - test.Assert(t, err == nil, err) - test.Assert(t, svrStream != nil, svrStream) - res, err = svrStream.Recv(ctx) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertBizErr(t, err) - - t.Logf("=== BidiStreamWithErr normalErr ===") - ctx = context.Background() - bidiStream, err := streamClient.BidiStreamWithErr(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, bidiStream != nil, bidiStream) - req = new(Request) - req.Type = normalErr - err = bidiStream.Send(ctx, req) - test.Assert(t, err == nil, err) - res, err = bidiStream.Recv(ctx) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertNormalErr(t, err) - - t.Logf("=== BidiStreamWithErr bizErr ===") - ctx = context.Background() - bidiStream, err = streamClient.BidiStreamWithErr(ctx) - test.Assert(t, err == nil, err) - test.Assert(t, bidiStream != nil, bidiStream) - req = new(Request) - req.Type = bizErr - err = bidiStream.Send(ctx, req) - test.Assert(t, err == nil, err) - res, err = bidiStream.Recv(ctx) - test.Assert(t, res == nil, res) - test.Assert(t, err != nil, err) - assertBizErr(t, err) -} diff --git a/pkg/streamx/streamx_common_test.go b/pkg/streamx/streamx_common_test.go new file mode 100644 index 0000000000..aa661d674b --- /dev/null +++ b/pkg/streamx/streamx_common_test.go @@ -0,0 +1,94 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package streamx_test + +import ( + "context" + "testing" + + "github.com/bytedance/gopkg/cloud/metainfo" + "github.com/cloudwego/gopkg/protocol/thrift" + "github.com/cloudwego/kitex/internal/test" + "github.com/cloudwego/kitex/pkg/kerrors" + "github.com/cloudwego/kitex/pkg/remote" +) + +const ( + normalErr int32 = iota + 1 + bizErr +) + +var ( + testCode = int32(10001) + testMsg = "biz testMsg" + testExtra = map[string]string{ + "testKey": "testVal", + } + normalErrMsg = "normal error" + + persistKVs = map[string]string{ + "p1": "v1", + "p2": "v2", + "p3": "v3", + } + transitKVs = map[string]string{ + "t1": "v1", + "t2": "v2", + "t3": "v3", + } +) + +func setMetadata(ctx context.Context) context.Context { + for k, v := range persistKVs { + ctx = metainfo.WithPersistentValue(ctx, k, v) + } + for k, v := range transitKVs { + ctx = metainfo.WithValue(ctx, k, v) + } + return ctx +} + +func validateMetadata(ctx context.Context) bool { + for k, v := range persistKVs { + _v, _ := metainfo.GetPersistentValue(ctx, k) + if _v != v { + return false + } + } + for k, v := range transitKVs { + _v, _ := metainfo.GetValue(ctx, k) + if _v != v { + return false + } + } + return true +} + +func assertNormalErr(t *testing.T, err error) { + ex, ok := err.(*thrift.ApplicationException) + test.Assert(t, ok, err) + test.Assert(t, ex.TypeID() == remote.InternalError, ex.TypeID()) + test.Assert(t, ex.Msg() == "biz error: "+normalErrMsg, ex.Msg()) +} + +func assertBizErr(t *testing.T, err error) { + bizIntf, ok := kerrors.FromBizStatusError(err) + test.Assert(t, ok) + test.Assert(t, bizIntf.BizStatusCode() == testCode, bizIntf.BizStatusCode()) + test.Assert(t, bizIntf.BizMessage() == testMsg, bizIntf.BizMessage()) + test.DeepEqual(t, bizIntf.BizExtra(), testExtra) +} diff --git a/pkg/streamx/provider/ttstream/ttstream_gen_codec_test.go b/pkg/streamx/streamx_gen_codec_test.go similarity index 99% rename from pkg/streamx/provider/ttstream/ttstream_gen_codec_test.go rename to pkg/streamx/streamx_gen_codec_test.go index 2784566ae9..129737b04e 100644 --- a/pkg/streamx/provider/ttstream/ttstream_gen_codec_test.go +++ b/pkg/streamx/streamx_gen_codec_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package ttstream_test +package streamx_test import ( "bytes" diff --git a/pkg/streamx/provider/ttstream/ttstream_gen_service_test.go b/pkg/streamx/streamx_gen_service_test.go similarity index 85% rename from pkg/streamx/provider/ttstream/ttstream_gen_service_test.go rename to pkg/streamx/streamx_gen_service_test.go index a7d8572c65..ea774a2cec 100644 --- a/pkg/streamx/provider/ttstream/ttstream_gen_service_test.go +++ b/pkg/streamx/streamx_gen_service_test.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package ttstream_test +package streamx_test import ( "context" @@ -31,19 +31,6 @@ import ( // === gen code === -// --- Define Header and Trailer type --- -type ( - ClientStreamingServer[Req, Res any] streamx.ClientStreamingServer[Req, Res] - ServerStreamingServer[Res any] streamx.ServerStreamingServer[Res] - BidiStreamingServer[Req, Res any] streamx.BidiStreamingServer[Req, Res] -) - -type ( - ClientStreamingClient[Req, Res any] streamx.ClientStreamingClient[Req, Res] - ServerStreamingClient[Res any] streamx.ServerStreamingClient[Res] - BidiStreamingClient[Req, Res any] streamx.BidiStreamingClient[Req, Res] -) - // --- Define Service Method handler --- var pingpongServiceInfo = &serviceinfo.ServiceInfo{ ServiceName: "kitex.service.pingpong", @@ -198,13 +185,13 @@ type PingPongServerInterface interface { } type StreamingServerInterface interface { Unary(ctx context.Context, req *Request) (*Response, error) - ClientStream(ctx context.Context, stream ClientStreamingServer[Request, Response]) (*Response, error) - ServerStream(ctx context.Context, req *Request, stream ServerStreamingServer[Response]) error - BidiStream(ctx context.Context, stream BidiStreamingServer[Request, Response]) error + ClientStream(ctx context.Context, stream streamx.ClientStreamingServer[Request, Response]) (*Response, error) + ServerStream(ctx context.Context, req *Request, stream streamx.ServerStreamingServer[Response]) error + BidiStream(ctx context.Context, stream streamx.BidiStreamingServer[Request, Response]) error UnaryWithErr(ctx context.Context, req *Request) (*Response, error) - ClientStreamWithErr(ctx context.Context, stream ClientStreamingServer[Request, Response]) (*Response, error) - ServerStreamWithErr(ctx context.Context, req *Request, stream ServerStreamingServer[Response]) error - BidiStreamWithErr(ctx context.Context, stream BidiStreamingServer[Request, Response]) error + ClientStreamWithErr(ctx context.Context, stream streamx.ClientStreamingServer[Request, Response]) (*Response, error) + ServerStreamWithErr(ctx context.Context, req *Request, stream streamx.ServerStreamingServer[Response]) error + BidiStreamWithErr(ctx context.Context, stream streamx.BidiStreamingServer[Request, Response]) error } // --- Define Client Implementation Interface --- @@ -215,18 +202,18 @@ type PingPongClientInterface interface { type StreamingClientInterface interface { Unary(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) (r *Response, err error) ClientStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream ClientStreamingClient[Request, Response], err error) + stream streamx.ClientStreamingClient[Request, Response], err error) ServerStream(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error) + stream streamx.ServerStreamingClient[Response], err error) BidiStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error) + stream streamx.BidiStreamingClient[Request, Response], err error) UnaryWithErr(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) (r *Response, err error) ClientStreamWithErr(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream ClientStreamingClient[Request, Response], err error) + stream streamx.ClientStreamingClient[Request, Response], err error) ServerStreamWithErr(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error) + stream streamx.ServerStreamingClient[Response], err error) BidiStreamWithErr(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error) + stream streamx.BidiStreamingClient[Request, Response], err error) } // --- Define Client Implementation --- @@ -260,20 +247,22 @@ func (c *kClient) Unary(ctx context.Context, req *Request, callOptions ...stream return res, nil } -func (c *kClient) ClientStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) (stream ClientStreamingClient[Request, Response], err error) { +func (c *kClient) ClientStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( + stream streamx.ClientStreamingClient[Request, Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingClient, "ClientStream", nil, nil, callOptions...) } func (c *kClient) ServerStream(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error, + stream streamx.ServerStreamingClient[Response], err error, ) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingServer, "ServerStream", req, nil, callOptions...) } func (c *kClient) BidiStream(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error, + stream streamx.BidiStreamingClient[Request, Response], err error, ) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingBidirectional, "BidiStream", nil, nil, callOptions...) @@ -289,20 +278,22 @@ func (c *kClient) UnaryWithErr(ctx context.Context, req *Request, callOptions .. return res, nil } -func (c *kClient) ClientStreamWithErr(ctx context.Context, callOptions ...streamxcallopt.CallOption) (stream ClientStreamingClient[Request, Response], err error) { +func (c *kClient) ClientStreamWithErr(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( + stream streamx.ClientStreamingClient[Request, Response], err error, +) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingClient, "ClientStreamWithErr", nil, nil, callOptions...) } func (c *kClient) ServerStreamWithErr(ctx context.Context, req *Request, callOptions ...streamxcallopt.CallOption) ( - stream ServerStreamingClient[Response], err error, + stream streamx.ServerStreamingClient[Response], err error, ) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingServer, "ServerStreamWithErr", req, nil, callOptions...) } func (c *kClient) BidiStreamWithErr(ctx context.Context, callOptions ...streamxcallopt.CallOption) ( - stream BidiStreamingClient[Request, Response], err error, + stream streamx.BidiStreamingClient[Request, Response], err error, ) { return streamxclient.InvokeStream[Request, Response]( ctx, c.streamer, serviceinfo.StreamingBidirectional, "BidiStreamWithErr", nil, nil, callOptions...) diff --git a/pkg/streamx/provider/ttstream/ttstream_server_test.go b/pkg/streamx/streamx_user_service_test.go similarity index 93% rename from pkg/streamx/provider/ttstream/ttstream_server_test.go rename to pkg/streamx/streamx_user_service_test.go index 7471471967..f701a31dc6 100644 --- a/pkg/streamx/provider/ttstream/ttstream_server_test.go +++ b/pkg/streamx/streamx_user_service_test.go @@ -14,13 +14,15 @@ * limitations under the License. */ -package ttstream_test +package streamx_test import ( "context" "errors" "io" + "testing" + "github.com/cloudwego/kitex/internal/test" "github.com/cloudwego/kitex/pkg/kerrors" "github.com/cloudwego/kitex/pkg/klog" "github.com/cloudwego/kitex/pkg/streamx" @@ -39,6 +41,15 @@ const ( trailerVal = "value1" ) +func testHeaderAndTrailer(t *testing.T, stream streamx.ClientStreamMetadata) { + hd, err := stream.Header() + test.Assert(t, err == nil, err) + test.Assert(t, hd[headerKey] == headerVal, hd) + tl, err := stream.Trailer() + test.Assert(t, err == nil, err) + test.Assert(t, tl[trailerKey] == trailerVal, tl) +} + func (si *streamingService) setHeaderAndTrailer(stream streamx.ServerStreamMetadata) error { err := stream.SetTrailer(streamx.Trailer{trailerKey: trailerVal}) if err != nil { diff --git a/pkg/streamx/streamx_user_test.go b/pkg/streamx/streamx_user_test.go new file mode 100644 index 0000000000..089bd89f00 --- /dev/null +++ b/pkg/streamx/streamx_user_test.go @@ -0,0 +1,603 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package streamx_test + +import ( + "context" + "errors" + "io" + "log" + "net/http" + _ "net/http/pprof" + "runtime" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/cloudwego/kitex/pkg/streamx" + "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream" + "github.com/cloudwego/netpoll" + + "github.com/cloudwego/kitex/client" + "github.com/cloudwego/kitex/client/streamxclient" + "github.com/cloudwego/kitex/internal/test" + "github.com/cloudwego/kitex/pkg/klog" + "github.com/cloudwego/kitex/pkg/remote/codec/thrift" + "github.com/cloudwego/kitex/server" + "github.com/cloudwego/kitex/server/streamxserver" + "github.com/cloudwego/kitex/transport" +) + +var providerTestCases []testCase + +type testCase struct { + Name string + ClientProvider streamx.ClientProvider + ServerProvider streamx.ServerProvider +} + +func init() { + klog.SetLevel(klog.LevelDebug) + + sp, _ := ttstream.NewServerProvider(streamingServiceInfo) + cp, _ := ttstream.NewClientProvider(streamingServiceInfo, ttstream.WithClientLongConnPool(ttstream.LongConnConfig{MaxIdleTimeout: time.Millisecond * 100})) + providerTestCases = append(providerTestCases, testCase{Name: "TTHeader_LongConn", ClientProvider: cp, ServerProvider: sp}) + cp, _ = ttstream.NewClientProvider(streamingServiceInfo, ttstream.WithClientShortConnPool()) + providerTestCases = append(providerTestCases, testCase{Name: "TTHeader_ShortConn", ClientProvider: cp, ServerProvider: sp}) + cp, _ = ttstream.NewClientProvider(streamingServiceInfo, ttstream.WithClientMuxConnPool()) + providerTestCases = append(providerTestCases, testCase{Name: "TTHeader_Mux", ClientProvider: cp, ServerProvider: sp}) +} + +func TestMain(m *testing.M) { + go func() { + log.Println(http.ListenAndServe("localhost:6060", nil)) + }() + m.Run() +} + +func TestStreamingBasic(t *testing.T) { + for _, tc := range providerTestCases { + t.Run(tc.Name, func(t *testing.T) { + // === prepare test environment === + addr := test.GetLocalAddress() + ln, err := netpoll.CreateListener("tcp", addr) + test.Assert(t, err == nil, err) + defer ln.Close() + // create server + var serverStreamCount int32 + waitServerStreamDone := func() { + for atomic.LoadInt32(&serverStreamCount) != 0 { + t.Logf("waitServerStreamDone: %d", atomic.LoadInt32(&serverStreamCount)) + time.Sleep(time.Millisecond * 10) + } + } + var serverRecvCount int32 + var serverSendCount int32 + svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) + // register pingpong service + err = svr.RegisterService(pingpongServiceInfo, new(pingpongService)) + test.Assert(t, err == nil, err) + // register streamingService as ttstreaam provider + err = svr.RegisterService( + streamingServiceInfo, + new(streamingService), + streamxserver.WithProvider(tc.ServerProvider), + streamxserver.WithStreamRecvMiddleware(func(next streamx.StreamRecvEndpoint) streamx.StreamRecvEndpoint { + return func(ctx context.Context, stream streamx.Stream, res any) (err error) { + err = next(ctx, stream, res) + if err == nil { + atomic.AddInt32(&serverRecvCount, 1) + } else { + log.Printf("server recv middleware err=%v", err) + } + return err + } + }), + streamxserver.WithStreamSendMiddleware(func(next streamx.StreamSendEndpoint) streamx.StreamSendEndpoint { + return func(ctx context.Context, stream streamx.Stream, req any) (err error) { + err = next(ctx, stream, req) + if err == nil { + atomic.AddInt32(&serverSendCount, 1) + } else { + log.Printf("server send middleware err=%v", err) + } + return err + } + }), + streamxserver.WithStreamMiddleware( + // middleware example: server streaming mode + func(next streamx.StreamEndpoint) streamx.StreamEndpoint { + return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { + log.Printf("Server middleware before next: reqArgs=%v resArgs=%v streamArgs=%v", + reqArgs.Req(), resArgs.Res(), streamArgs) + test.Assert(t, streamArgs.Stream() != nil) + test.Assert(t, validateMetadata(ctx)) + + switch streamArgs.Stream().Mode() { + case streamx.StreamingUnary: + test.Assert(t, reqArgs.Req() != nil) + test.Assert(t, resArgs.Res() == nil) + err = next(ctx, streamArgs, reqArgs, resArgs) + test.Assert(t, reqArgs.Req() != nil) + test.Assert(t, resArgs.Res() != nil || err != nil) + case streamx.StreamingClient: + test.Assert(t, reqArgs.Req() == nil) + test.Assert(t, resArgs.Res() == nil) + err = next(ctx, streamArgs, reqArgs, resArgs) + test.Assert(t, reqArgs.Req() == nil) + test.Assert(t, resArgs.Res() != nil || err != nil) + case streamx.StreamingServer: + test.Assert(t, reqArgs.Req() != nil) + test.Assert(t, resArgs.Res() == nil) + err = next(ctx, streamArgs, reqArgs, resArgs) + test.Assert(t, reqArgs.Req() != nil) + test.Assert(t, resArgs.Res() == nil) + case streamx.StreamingBidirectional: + test.Assert(t, reqArgs.Req() == nil) + test.Assert(t, resArgs.Res() == nil) + err = next(ctx, streamArgs, reqArgs, resArgs) + test.Assert(t, reqArgs.Req() == nil) + test.Assert(t, resArgs.Res() == nil) + } + + log.Printf("Server middleware after next: reqArgs=%v resArgs=%v streamArgs=%v err=%v", + reqArgs.Req(), resArgs.Res(), streamArgs.Stream(), err) + atomic.AddInt32(&serverStreamCount, 1) + return err + } + }, + ), + ) + test.Assert(t, err == nil, err) + go func() { + err := svr.Run() + test.Assert(t, err == nil, err) + }() + defer svr.Stop() + test.WaitServerStart(addr) + + // create client + pingpongClient, err := NewPingPongClient( + "kitex.service.pingpong", + client.WithHostPorts(addr), + client.WithTransportProtocol(transport.TTHeaderFramed), + client.WithPayloadCodec(thrift.NewThriftCodecWithConfig(thrift.FastRead|thrift.FastWrite|thrift.EnableSkipDecoder)), + ) + test.Assert(t, err == nil, err) + // create streaming client + streamClient, err := NewStreamingClient( + "kitex.service.streaming", + streamxclient.WithProvider(tc.ClientProvider), + streamxclient.WithHostPorts(addr), + streamxclient.WithStreamRecvMiddleware(func(next streamx.StreamRecvEndpoint) streamx.StreamRecvEndpoint { + return func(ctx context.Context, stream streamx.Stream, res any) (err error) { + err = next(ctx, stream, res) + return err + } + }), + streamxclient.WithStreamSendMiddleware(func(next streamx.StreamSendEndpoint) streamx.StreamSendEndpoint { + return func(ctx context.Context, stream streamx.Stream, req any) (err error) { + err = next(ctx, stream, req) + return err + } + }), + streamxclient.WithStreamMiddleware(func(next streamx.StreamEndpoint) streamx.StreamEndpoint { + return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { + // validate ctx + test.Assert(t, validateMetadata(ctx)) + + err = next(ctx, streamArgs, reqArgs, resArgs) + + test.Assert(t, streamArgs.Stream() != nil) + switch streamArgs.Stream().Mode() { + case streamx.StreamingUnary: + test.Assert(t, reqArgs.Req() != nil) + test.Assert(t, resArgs.Res() != nil || err != nil) + case streamx.StreamingClient: + test.Assert(t, reqArgs.Req() == nil, reqArgs.Req()) + test.Assert(t, resArgs.Res() == nil) + case streamx.StreamingServer: + test.Assert(t, reqArgs.Req() != nil) + test.Assert(t, resArgs.Res() == nil) + case streamx.StreamingBidirectional: + test.Assert(t, reqArgs.Req() == nil) + test.Assert(t, resArgs.Res() == nil) + } + return err + } + }), + ) + test.Assert(t, err == nil, err) + + // prepare metainfo + ctx := context.Background() + ctx = setMetadata(ctx) + + t.Logf("=== PingPong ===") + req := new(Request) + req.Message = "PingPong" + res, err := pingpongClient.PingPong(ctx, req) + test.Assert(t, err == nil, err) + test.Assert(t, req.Message == res.Message, res) + + t.Logf("=== Unary ===") + req = new(Request) + req.Type = 10000 + req.Message = "Unary" + res, err = streamClient.Unary(ctx, req) + test.Assert(t, err == nil, err) + test.Assert(t, req.Type == res.Type, res.Type) + test.Assert(t, req.Message == res.Message, res.Message) + test.Assert(t, serverRecvCount == 1, serverRecvCount) + test.Assert(t, serverSendCount == 1, serverSendCount) + atomic.AddInt32(&serverStreamCount, -1) + waitServerStreamDone() + serverRecvCount = 0 + serverSendCount = 0 + + // client stream + round := 5 + t.Logf("=== ClientStream ===") + cs, err := streamClient.ClientStream(ctx) + test.Assert(t, err == nil, err) + for i := 0; i < round; i++ { + req := new(Request) + req.Type = int32(i) + req.Message = "ClientStream" + err = cs.Send(ctx, req) + test.Assert(t, err == nil, err) + } + res, err = cs.CloseAndRecv(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, res.Message == "ClientStream", res.Message) + atomic.AddInt32(&serverStreamCount, -1) + waitServerStreamDone() + test.DeepEqual(t, serverRecvCount, int32(round)) + test.Assert(t, serverSendCount == 1, serverSendCount) + testHeaderAndTrailer(t, cs) + cs = nil + serverRecvCount = 0 + serverSendCount = 0 + runtime.GC() + + // server stream + t.Logf("=== ServerStream ===") + req = new(Request) + req.Message = "ServerStream" + ss, err := streamClient.ServerStream(ctx, req) + test.Assert(t, err == nil, err) + received := 0 + for { + res, err := ss.Recv(ctx) + if errors.Is(err, io.EOF) { + break + } + test.Assert(t, err == nil, err) + received++ + t.Logf("Client ServerStream recv: %v", res) + } + err = ss.CloseSend(ctx) + test.Assert(t, err == nil, err) + atomic.AddInt32(&serverStreamCount, -1) + waitServerStreamDone() + test.Assert(t, serverRecvCount == 1, serverRecvCount) + test.Assert(t, serverSendCount == int32(received), serverSendCount, received) + testHeaderAndTrailer(t, ss) + ss = nil + serverRecvCount = 0 + serverSendCount = 0 + runtime.GC() + + // bidi stream + t.Logf("=== BidiStream ===") + concurrent := 32 + round = 5 + for c := 0; c < concurrent; c++ { + atomic.AddInt32(&serverStreamCount, -1) + go func() { + bs, err := streamClient.BidiStream(ctx) + test.Assert(t, err == nil, err) + msg := "BidiStream" + var wg sync.WaitGroup + wg.Add(2) + go func() { + defer wg.Done() + for i := 0; i < round; i++ { + req := new(Request) + req.Message = msg + err := bs.Send(ctx, req) + test.Assert(t, err == nil, err) + } + err = bs.CloseSend(ctx) + test.Assert(t, err == nil, err) + }() + go func() { + defer wg.Done() + i := 0 + for { + res, err := bs.Recv(ctx) + t.Log(res, err) + if errors.Is(err, io.EOF) { + break + } + i++ + test.Assert(t, err == nil, err) + test.Assert(t, msg == res.Message, res.Message) + } + test.Assert(t, i == round, i) + }() + testHeaderAndTrailer(t, bs) + }() + } + waitServerStreamDone() + test.Assert(t, serverRecvCount == int32(concurrent*round), serverRecvCount) + test.Assert(t, serverSendCount == int32(concurrent*round), serverSendCount) + serverRecvCount = 0 + serverSendCount = 0 + runtime.GC() + + t.Logf("=== UnaryWithErr normalErr ===") + req = new(Request) + req.Type = normalErr + res, err = streamClient.UnaryWithErr(ctx, req) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertNormalErr(t, err) + + t.Logf("=== UnaryWithErr bizErr ===") + req = new(Request) + req.Type = bizErr + res, err = streamClient.UnaryWithErr(ctx, req) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertBizErr(t, err) + + t.Logf("=== ClientStreamWithErr normalErr ===") + cliStream, err := streamClient.ClientStreamWithErr(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, cliStream != nil, cliStream) + req = new(Request) + req.Type = normalErr + err = cliStream.Send(ctx, req) + test.Assert(t, err == nil, err) + res, err = cliStream.CloseAndRecv(ctx) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertNormalErr(t, err) + + t.Logf("=== ClientStreamWithErr bizErr ===") + cliStream, err = streamClient.ClientStreamWithErr(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, cliStream != nil, cliStream) + req = new(Request) + req.Type = bizErr + err = cliStream.Send(ctx, req) + test.Assert(t, err == nil, err) + res, err = cliStream.CloseAndRecv(ctx) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertBizErr(t, err) + + t.Logf("=== ServerStreamWithErr normalErr ===") + req = new(Request) + req.Type = normalErr + svrStream, err := streamClient.ServerStreamWithErr(ctx, req) + test.Assert(t, err == nil, err) + test.Assert(t, svrStream != nil, svrStream) + res, err = svrStream.Recv(ctx) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertNormalErr(t, err) + + t.Logf("=== ServerStreamWithErr bizErr ===") + req = new(Request) + req.Type = bizErr + svrStream, err = streamClient.ServerStreamWithErr(ctx, req) + test.Assert(t, err == nil, err) + test.Assert(t, svrStream != nil, svrStream) + res, err = svrStream.Recv(ctx) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertBizErr(t, err) + + t.Logf("=== BidiStreamWithErr normalErr ===") + bidiStream, err := streamClient.BidiStreamWithErr(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, bidiStream != nil, bidiStream) + req = new(Request) + req.Type = normalErr + err = bidiStream.Send(ctx, req) + test.Assert(t, err == nil, err) + res, err = bidiStream.Recv(ctx) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertNormalErr(t, err) + + t.Logf("=== BidiStreamWithErr bizErr ===") + bidiStream, err = streamClient.BidiStreamWithErr(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, bidiStream != nil, bidiStream) + req = new(Request) + req.Type = bizErr + err = bidiStream.Send(ctx, req) + test.Assert(t, err == nil, err) + res, err = bidiStream.Recv(ctx) + test.Assert(t, res == nil, res) + test.Assert(t, err != nil, err) + assertBizErr(t, err) + + t.Logf("=== Timeout by Ctx ===") + bs, err := streamClient.BidiStream(ctx) + test.Assert(t, err == nil, err) + req = new(Request) + req.Message = string(make([]byte, 1024)) + err = bs.Send(ctx, req) + test.Assert(t, err == nil, err) + nctx, cancel := context.WithCancel(ctx) + cancel() + _, err = bs.Recv(nctx) + test.Assert(t, err != nil, err) + t.Logf("recv timeout error: %v", err) + err = bs.CloseSend(ctx) + test.Assert(t, err == nil, err) + + // timeout by client WithRecvTimeout + t.Logf("=== Timeout by WithRecvTimeout ===") + streamClient, _ = NewStreamingClient( + "kitex.service.streaming", + streamxclient.WithHostPorts(addr), + streamxclient.WithProvider(tc.ClientProvider), + streamxclient.WithRecvTimeout(time.Nanosecond), + ) + bs, err = streamClient.BidiStream(ctx) + test.Assert(t, err == nil, err) + req = new(Request) + req.Message = string(make([]byte, 1024)) + err = bs.Send(ctx, req) + test.Assert(t, err == nil, err) + _, err = bs.Recv(ctx) + test.Assert(t, err != nil, err) + t.Logf("recv timeout error: %v", err) + err = bs.CloseSend(ctx) + test.Assert(t, err == nil, err) + + streamClient = nil + }) + } +} + +func TestStreamingGoroutineLeak(t *testing.T) { + for _, tc := range providerTestCases { + t.Run(tc.Name, func(t *testing.T) { + addr := test.GetLocalAddress() + ln, _ := netpoll.CreateListener("tcp", addr) + defer ln.Close() + + // create server + svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) + var streamStarted int32 + waitStreamStarted := func(waitStreams int) { + for atomic.LoadInt32(&streamStarted) < int32(waitStreams) { + time.Sleep(time.Millisecond * 10) + t.Logf("streamStarted=%d < waitStreams=%d", atomic.LoadInt32(&streamStarted), waitStreams) + } + } + _ = svr.RegisterService( + streamingServiceInfo, new(streamingService), + streamxserver.WithProvider(tc.ServerProvider), + streamxserver.WithStreamMiddleware(func(next streamx.StreamEndpoint) streamx.StreamEndpoint { + return func(ctx context.Context, streamArgs streamx.StreamArgs, reqArgs streamx.StreamReqArgs, resArgs streamx.StreamResArgs) (err error) { + atomic.AddInt32(&streamStarted, 1) + return next(ctx, streamArgs, reqArgs, resArgs) + } + }), + ) + go func() { + _ = svr.Run() + }() + defer svr.Stop() + test.WaitServerStart(addr) + + streamClient, _ := NewStreamingClient( + "kitex.service.streaming", + streamxclient.WithHostPorts(addr), + streamxclient.WithProvider(tc.ClientProvider), + ) + ctx := context.Background() + msg := "BidiStream" + + t.Logf("=== Checking only one connection be reused ===") + var wg sync.WaitGroup + for i := 0; i < 12; i++ { + wg.Add(1) + bs, err := streamClient.BidiStream(ctx) + test.Assert(t, err == nil, err) + req := new(Request) + req.Message = string(make([]byte, 1024)) + err = bs.Send(ctx, req) + test.Assert(t, err == nil, err) + res, err := bs.Recv(ctx) + test.Assert(t, err == nil, err) + err = bs.CloseSend(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, res.Message == req.Message, res.Message) + runtime.SetFinalizer(bs, func(_ any) { + wg.Done() + t.Logf("stream is finalized") + }) + bs = nil + runtime.GC() + wg.Wait() + } + + t.Logf("=== Checking Streams GCed ===") + oldNGs := runtime.NumGoroutine() + streams := 100 + streamList := make([]streamx.ServerStream, streams) + atomic.StoreInt32(&streamStarted, 0) + for i := 0; i < streams; i++ { + ctx := context.Background() + bs, err := streamClient.BidiStream(ctx) + test.Assert(t, err == nil, err) + streamList[i] = bs + } + waitStreamStarted(streams) + ngs := runtime.NumGoroutine() + test.Assert(t, ngs > streams, ngs) + for i := 0; i < streams; i++ { + streamList[i] = nil + } + for ngs-oldNGs > 10 { + runtime.GC() + ngs = runtime.NumGoroutine() + time.Sleep(time.Millisecond * 50) + } + + t.Logf("=== Checking Streams Called and GCed ===") + streams = 100 + for i := 0; i < streams; i++ { + wg.Add(1) + go func() { + bs, err := streamClient.BidiStream(ctx) + test.Assert(t, err == nil, err) + req := new(Request) + req.Message = msg + err = bs.Send(ctx, req) + test.Assert(t, err == nil, err) + go func() { + defer wg.Done() + res, err := bs.Recv(ctx) + test.Assert(t, err == nil, err) + err = bs.CloseSend(ctx) + test.Assert(t, err == nil, err) + test.Assert(t, res.Message == msg, res.Message) + + testHeaderAndTrailer(t, bs) + }() + }() + } + wg.Wait() + ngs = runtime.NumGoroutine() + for ngs-oldNGs > 10 { + runtime.GC() + ngs = runtime.NumGoroutine() + time.Sleep(time.Millisecond * 50) + } + }) + } +} From e1f662da3ce7fe6921b10adbf9beed1a344d76de Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 17:39:31 +0800 Subject: [PATCH 05/13] chore: add license --- client/client_streamx.go | 16 ++++++++++++++++ client/streamxclient/client.go | 16 ++++++++++++++++ client/streamxclient/client_gen.go | 16 ++++++++++++++++ client/streamxclient/client_option.go | 16 ++++++++++++++++ .../streamxclient/streamxcallopt/call_option.go | 16 ++++++++++++++++ pkg/streamx/client_options.go | 16 ++++++++++++++++ pkg/streamx/header_trailer.go | 16 ++++++++++++++++ .../provider/ttstream/container/object_pool.go | 16 ++++++++++++++++ .../provider/ttstream/container/stack_test.go | 16 ++++++++++++++++ pkg/streamx/provider/ttstream/exception.go | 16 ++++++++++++++++ pkg/streamx/stream_middleware_internal.go | 16 ++++++++++++++++ server/streamxserver/server.go | 16 ++++++++++++++++ server/streamxserver/server_gen.go | 16 ++++++++++++++++ server/streamxserver/server_option.go | 16 ++++++++++++++++ tool/internal_pkg/tpl/streamx/client.go | 16 ++++++++++++++++ tool/internal_pkg/tpl/streamx/handler.method.go | 16 ++++++++++++++++ tool/internal_pkg/tpl/streamx/server.go | 16 ++++++++++++++++ tool/internal_pkg/tpl/streamx/service.go | 16 ++++++++++++++++ 18 files changed, 288 insertions(+) diff --git a/client/client_streamx.go b/client/client_streamx.go index 60d1e767bf..6a0fcb769c 100644 --- a/client/client_streamx.go +++ b/client/client_streamx.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package client import ( diff --git a/client/streamxclient/client.go b/client/streamxclient/client.go index 5bd52d8888..09f52707b3 100644 --- a/client/streamxclient/client.go +++ b/client/streamxclient/client.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxclient import ( diff --git a/client/streamxclient/client_gen.go b/client/streamxclient/client_gen.go index eb1e68f530..001d03c149 100644 --- a/client/streamxclient/client_gen.go +++ b/client/streamxclient/client_gen.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxclient import ( diff --git a/client/streamxclient/client_option.go b/client/streamxclient/client_option.go index bcc101dc63..0534b305a3 100644 --- a/client/streamxclient/client_option.go +++ b/client/streamxclient/client_option.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxclient import ( diff --git a/client/streamxclient/streamxcallopt/call_option.go b/client/streamxclient/streamxcallopt/call_option.go index c4acd957fd..de48a90ac9 100644 --- a/client/streamxclient/streamxcallopt/call_option.go +++ b/client/streamxclient/streamxcallopt/call_option.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxcallopt import ( diff --git a/pkg/streamx/client_options.go b/pkg/streamx/client_options.go index 9beb142357..935ad0d61b 100644 --- a/pkg/streamx/client_options.go +++ b/pkg/streamx/client_options.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx import ( diff --git a/pkg/streamx/header_trailer.go b/pkg/streamx/header_trailer.go index 1c5372a985..50c2bbeaef 100644 --- a/pkg/streamx/header_trailer.go +++ b/pkg/streamx/header_trailer.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx type ( diff --git a/pkg/streamx/provider/ttstream/container/object_pool.go b/pkg/streamx/provider/ttstream/container/object_pool.go index 26fdc26978..28aba9e159 100644 --- a/pkg/streamx/provider/ttstream/container/object_pool.go +++ b/pkg/streamx/provider/ttstream/container/object_pool.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package container import ( diff --git a/pkg/streamx/provider/ttstream/container/stack_test.go b/pkg/streamx/provider/ttstream/container/stack_test.go index 420bd636b5..2a5eee2eac 100644 --- a/pkg/streamx/provider/ttstream/container/stack_test.go +++ b/pkg/streamx/provider/ttstream/container/stack_test.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package container import ( diff --git a/pkg/streamx/provider/ttstream/exception.go b/pkg/streamx/provider/ttstream/exception.go index 5c650784b2..17f51b157d 100644 --- a/pkg/streamx/provider/ttstream/exception.go +++ b/pkg/streamx/provider/ttstream/exception.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package ttstream type tException interface { diff --git a/pkg/streamx/stream_middleware_internal.go b/pkg/streamx/stream_middleware_internal.go index ab2d9f35f0..d06d7d491d 100644 --- a/pkg/streamx/stream_middleware_internal.go +++ b/pkg/streamx/stream_middleware_internal.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx import ( diff --git a/server/streamxserver/server.go b/server/streamxserver/server.go index 890040e190..adfeb73432 100644 --- a/server/streamxserver/server.go +++ b/server/streamxserver/server.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxserver import ( diff --git a/server/streamxserver/server_gen.go b/server/streamxserver/server_gen.go index c417b0cff3..c92c8692b9 100644 --- a/server/streamxserver/server_gen.go +++ b/server/streamxserver/server_gen.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxserver import ( diff --git a/server/streamxserver/server_option.go b/server/streamxserver/server_option.go index e6e04415b5..6869dcc8b5 100644 --- a/server/streamxserver/server_option.go +++ b/server/streamxserver/server_option.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamxserver import ( diff --git a/tool/internal_pkg/tpl/streamx/client.go b/tool/internal_pkg/tpl/streamx/client.go index f88fce814e..2a5e88ca2b 100644 --- a/tool/internal_pkg/tpl/streamx/client.go +++ b/tool/internal_pkg/tpl/streamx/client.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx var ClientTpl = `// Code generated by Kitex {{.Version}}. DO NOT EDIT. diff --git a/tool/internal_pkg/tpl/streamx/handler.method.go b/tool/internal_pkg/tpl/streamx/handler.method.go index 0224237e3d..acbbdd7571 100644 --- a/tool/internal_pkg/tpl/streamx/handler.method.go +++ b/tool/internal_pkg/tpl/streamx/handler.method.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx var HandlerMethodsTpl = `{{define "HandlerMethod"}} diff --git a/tool/internal_pkg/tpl/streamx/server.go b/tool/internal_pkg/tpl/streamx/server.go index 217c7b3fa1..08eaa64483 100644 --- a/tool/internal_pkg/tpl/streamx/server.go +++ b/tool/internal_pkg/tpl/streamx/server.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx var ServerTpl = `// Code generated by Kitex {{.Version}}. DO NOT EDIT. diff --git a/tool/internal_pkg/tpl/streamx/service.go b/tool/internal_pkg/tpl/streamx/service.go index cbd727d5d0..d9bad47462 100644 --- a/tool/internal_pkg/tpl/streamx/service.go +++ b/tool/internal_pkg/tpl/streamx/service.go @@ -1,3 +1,19 @@ +/* + * Copyright 2024 CloudWeGo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package streamx var ServiceTpl = `// Code generated by Kitex {{.Version}}. DO NOT EDIT. From 2d7a97a94d66b9c6be257961c8502a0c71a08247 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 17:40:10 +0800 Subject: [PATCH 06/13] fix lint --- pkg/remote/trans/streamx/server_handler.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/remote/trans/streamx/server_handler.go b/pkg/remote/trans/streamx/server_handler.go index 4db789d232..73490ad261 100644 --- a/pkg/remote/trans/streamx/server_handler.go +++ b/pkg/remote/trans/streamx/server_handler.go @@ -61,8 +61,10 @@ func (f *svrTransHandlerFactory) NewTransHandler(opt *remote.ServerOption) (remo }, nil } -var _ remote.ServerTransHandler = &svrTransHandler{} -var errProtocolNotMatch = errors.New("protocol not match") +var ( + _ remote.ServerTransHandler = &svrTransHandler{} + errProtocolNotMatch = errors.New("protocol not match") +) type svrTransHandler struct { opt *remote.ServerOption From 2def2a621562b44e6bd1c0dc7158d5edc8f507b7 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Wed, 16 Oct 2024 17:50:05 +0800 Subject: [PATCH 07/13] fix lint --- pkg/streamx/provider/jsonrpc/protocol.go | 2 +- pkg/streamx/provider/ttstream/client_trans_pool.go | 2 +- pkg/streamx/provider/ttstream/client_trans_pool_longconn.go | 2 +- pkg/streamx/provider/ttstream/client_trans_pool_mux.go | 4 ++-- pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go | 2 +- pkg/streamx/provider/ttstream/container/object_pool.go | 2 +- pkg/streamx/provider/ttstream/container/stack.go | 2 +- pkg/streamx/provider/ttstream/container/stack_test.go | 4 ++-- pkg/streamx/provider/ttstream/meta_frame_handler.go | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/streamx/provider/jsonrpc/protocol.go b/pkg/streamx/provider/jsonrpc/protocol.go index b3f528111d..cbac87b90d 100644 --- a/pkg/streamx/provider/jsonrpc/protocol.go +++ b/pkg/streamx/provider/jsonrpc/protocol.go @@ -78,7 +78,7 @@ type Frame struct { payload []byte } -func newFrame(typ int, sid int, service, method string, payload []byte) Frame { +func newFrame(typ, sid int, service, method string, payload []byte) Frame { return Frame{ typ: typ, sid: sid, diff --git a/pkg/streamx/provider/ttstream/client_trans_pool.go b/pkg/streamx/provider/ttstream/client_trans_pool.go index 261052deab..78be57754d 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool.go @@ -24,6 +24,6 @@ import ( var dialer = netpoll.NewDialer() type transPool interface { - Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (trans *transport, err error) + Get(sinfo *serviceinfo.ServiceInfo, network, addr string) (trans *transport, err error) Put(trans *transport) } diff --git a/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go b/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go index 47e9d9e11e..bae4f6ec6e 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool_longconn.go @@ -46,7 +46,7 @@ type longConnTransPool struct { config LongConnConfig } -func (c *longConnTransPool) Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (trans *transport, err error) { +func (c *longConnTransPool) Get(sinfo *serviceinfo.ServiceInfo, network, addr string) (trans *transport, err error) { for { o := c.transPool.Pop(addr) if o == nil { diff --git a/pkg/streamx/provider/ttstream/client_trans_pool_mux.go b/pkg/streamx/provider/ttstream/client_trans_pool_mux.go index 441fb02135..d0d9fc8a60 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool_mux.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool_mux.go @@ -44,7 +44,7 @@ func newMuxTransList(size int) *muxTransList { return tl } -func (tl *muxTransList) Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (*transport, error) { +func (tl *muxTransList) Get(sinfo *serviceinfo.ServiceInfo, network, addr string) (*transport, error) { idx := atomic.AddUint32(&tl.cursor, 1) % uint32(tl.size) tl.L.RLock() trans := tl.transports[idx] @@ -85,7 +85,7 @@ type muxTransPool struct { sflight singleflight.Group } -func (m *muxTransPool) Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (trans *transport, err error) { +func (m *muxTransPool) Get(sinfo *serviceinfo.ServiceInfo, network, addr string) (trans *transport, err error) { v, ok := m.pool.Load(addr) if ok { return v.(*muxTransList).Get(sinfo, network, addr) diff --git a/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go b/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go index 5346273847..e5eb081520 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool_shortconn.go @@ -28,7 +28,7 @@ func newShortConnTransPool() transPool { type shortConnTransPool struct{} -func (c *shortConnTransPool) Get(sinfo *serviceinfo.ServiceInfo, network string, addr string) (*transport, error) { +func (c *shortConnTransPool) Get(sinfo *serviceinfo.ServiceInfo, network, addr string) (*transport, error) { // create new connection conn, err := dialer.DialConnection(network, addr, time.Second) if err != nil { diff --git a/pkg/streamx/provider/ttstream/container/object_pool.go b/pkg/streamx/provider/ttstream/container/object_pool.go index 28aba9e159..28b7f3bb4c 100644 --- a/pkg/streamx/provider/ttstream/container/object_pool.go +++ b/pkg/streamx/provider/ttstream/container/object_pool.go @@ -98,7 +98,7 @@ func (s *ObjectPool) cleaning() { deleted := 0 var oldest *time.Time klog.Infof("object[%s] pool cleaning %d objects", key, stk.Size()) - stk.RangeDelete(func(o objectItem) (deleteNode bool, continueRange bool) { + stk.RangeDelete(func(o objectItem) (deleteNode, continueRange bool) { if oldest == nil { oldest = &o.lastActive } diff --git a/pkg/streamx/provider/ttstream/container/stack.go b/pkg/streamx/provider/ttstream/container/stack.go index 7083fc27e0..e9a0a883c1 100644 --- a/pkg/streamx/provider/ttstream/container/stack.go +++ b/pkg/streamx/provider/ttstream/container/stack.go @@ -40,7 +40,7 @@ func (s *Stack[ValueType]) Size() (size int) { } // RangeDelete range from the stack bottom -func (s *Stack[ValueType]) RangeDelete(checking func(v ValueType) (deleteNode bool, continueRange bool)) { +func (s *Stack[ValueType]) RangeDelete(checking func(v ValueType) (deleteNode, continueRange bool)) { // Stop the world! s.L.Lock() // range from the stack bottom(oldest item) diff --git a/pkg/streamx/provider/ttstream/container/stack_test.go b/pkg/streamx/provider/ttstream/container/stack_test.go index 2a5eee2eac..fe08d64ce9 100644 --- a/pkg/streamx/provider/ttstream/container/stack_test.go +++ b/pkg/streamx/provider/ttstream/container/stack_test.go @@ -91,12 +91,12 @@ func TestStackRangeDelete(t *testing.T) { for i := 1; i <= round; i++ { stk.Push(i) } - stk.RangeDelete(func(v int) (deleteNode bool, continueRange bool) { + stk.RangeDelete(func(v int) (deleteNode, continueRange bool) { return v%2 == 0, true }) test.Assert(t, stk.Size() == round/2, stk.Size()) size := 0 - stk.RangeDelete(func(v int) (deleteNode bool, continueRange bool) { + stk.RangeDelete(func(v int) (deleteNode, continueRange bool) { size++ return false, true }) diff --git a/pkg/streamx/provider/ttstream/meta_frame_handler.go b/pkg/streamx/provider/ttstream/meta_frame_handler.go index 35c3f5f67c..e5dd6a54dc 100644 --- a/pkg/streamx/provider/ttstream/meta_frame_handler.go +++ b/pkg/streamx/provider/ttstream/meta_frame_handler.go @@ -25,7 +25,7 @@ import ( type StreamMeta interface { Meta() map[string]string GetMeta(k string) (string, bool) - SetMeta(k string, v string, kvs ...string) + SetMeta(k, v string, kvs ...string) } type MetaFrameHandler interface { @@ -60,7 +60,7 @@ func (s *streamMeta) GetMeta(k string) (string, bool) { return v, ok } -func (s *streamMeta) SetMeta(k string, v string, kvs ...string) { +func (s *streamMeta) SetMeta(k, v string, kvs ...string) { s.sync.RLock() s.data[k] = v for i := 0; i < len(kvs); i += 2 { From dc53af2782fad5c425b154d1772de6b42a4a6775 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Thu, 17 Oct 2024 14:28:35 +0800 Subject: [PATCH 08/13] fix: pipe dead lock --- .../provider/ttstream/container/pipe.go | 37 ++++++++++--------- .../provider/ttstream/container/pipe_test.go | 13 ++++++- pkg/streamx/provider/ttstream/stream.go | 2 +- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/pkg/streamx/provider/ttstream/container/pipe.go b/pkg/streamx/provider/ttstream/container/pipe.go index 791670261b..a2c8254354 100644 --- a/pkg/streamx/provider/ttstream/container/pipe.go +++ b/pkg/streamx/provider/ttstream/container/pipe.go @@ -33,9 +33,9 @@ const ( ) var ( - ErrPipeEOF = io.EOF - ErrPipeCanceled = fmt.Errorf("pipe canceled") - stateErrors map[pipeState]error = map[pipeState]error{ + ErrPipeEOF = io.EOF + ErrPipeCanceled = fmt.Errorf("pipe canceled") + stateErrors = map[pipeState]error{ pipeStateClosed: ErrPipeEOF, pipeStateCanceled: ErrPipeCanceled, } @@ -51,14 +51,13 @@ type Pipe[Item any] struct { func NewPipe[Item any]() *Pipe[Item] { p := new(Pipe[Item]) p.queue = NewQueue[Item]() - p.trigger = make(chan struct{}) + p.trigger = make(chan struct{}, 1) return p } // Read will block if there is nothing to read -func (p *Pipe[Item]) Read(ctx context.Context, items []Item) (int, error) { +func (p *Pipe[Item]) Read(ctx context.Context, items []Item) (n int, err error) { READ: - var n int for i := 0; i < len(items); i++ { val, ok := p.queue.Get() if !ok { @@ -84,22 +83,22 @@ READ: } if p.queue.Size() == 0 { - err := stateErrors[atomic.LoadInt32(&p.state)] + err = stateErrors[atomic.LoadInt32(&p.state)] if err != nil { return 0, err } - return 0, fmt.Errorf("unknown err") } goto READ } } -func (p *Pipe[Item]) Write(ctx context.Context, items ...Item) error { +func (p *Pipe[Item]) Write(ctx context.Context, items ...Item) (err error) { if !atomic.CompareAndSwapInt32(&p.state, pipeStateInactive, pipeStateActive) && atomic.LoadInt32(&p.state) != pipeStateActive { - err := stateErrors[atomic.LoadInt32(&p.state)] + err = stateErrors[atomic.LoadInt32(&p.state)] if err != nil { return err } + // never happen error return fmt.Errorf("unknown state error") } @@ -115,19 +114,21 @@ func (p *Pipe[Item]) Write(ctx context.Context, items ...Item) error { } func (p *Pipe[Item]) Close() { - select { - case <-p.trigger: - default: + if atomic.LoadInt32(&p.state) != pipeStateClosed { atomic.StoreInt32(&p.state, pipeStateClosed) - close(p.trigger) + select { + case p.trigger <- struct{}{}: + default: + } } } func (p *Pipe[Item]) Cancel() { - select { - case <-p.trigger: - default: + if atomic.LoadInt32(&p.state) != pipeStateCanceled { atomic.StoreInt32(&p.state, pipeStateCanceled) - close(p.trigger) + select { + case p.trigger <- struct{}{}: + default: + } } } diff --git a/pkg/streamx/provider/ttstream/container/pipe_test.go b/pkg/streamx/provider/ttstream/container/pipe_test.go index 761589d30b..7475fd13d8 100644 --- a/pkg/streamx/provider/ttstream/container/pipe_test.go +++ b/pkg/streamx/provider/ttstream/container/pipe_test.go @@ -18,6 +18,7 @@ package container import ( "context" + "io" "sync" "testing" ) @@ -34,6 +35,9 @@ func TestPipeline(t *testing.T) { for { n, err := pipe.Read(ctx, items) if err != nil { + if err != io.EOF { + t.Error(err) + } return } for i := 0; i < n; i++ { @@ -44,12 +48,17 @@ func TestPipeline(t *testing.T) { round := 10000 itemsPerRound := []int{1, 1, 1, 1, 1} for i := 0; i < round; i++ { - _ = pipe.Write(ctx, itemsPerRound...) + err := pipe.Write(ctx, itemsPerRound...) + if err != nil { + t.Fatal(err) + } } + t.Logf("Pipe closing") pipe.Close() + t.Logf("Pipe closed") wg.Wait() if recv != len(itemsPerRound)*round { - t.Fatalf("expect %d items, got %d", len(itemsPerRound)*round, recv) + t.Fatalf("Pipe expect %d items, got %d", len(itemsPerRound)*round, recv) } } diff --git a/pkg/streamx/provider/ttstream/stream.go b/pkg/streamx/provider/ttstream/stream.go index d0de8bf45e..3bdb35dc25 100644 --- a/pkg/streamx/provider/ttstream/stream.go +++ b/pkg/streamx/provider/ttstream/stream.go @@ -206,7 +206,7 @@ func (s *stream) sendTrailer(ctx context.Context, ex tException) (err error) { if wtrailer == nil { return fmt.Errorf("stream trailer already sent") } - klog.Debugf("transport[%d]-stream[%d] send trialer", s.trans.kind, s.sid) + klog.Debugf("transport[%d]-stream[%d] send trailer", s.trans.kind, s.sid) return s.trans.streamCloseSend(s.sid, s.method, wtrailer, ex) } From 5a6f41fad6f81ce6f02045b006d899bfd23c0bec Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Thu, 17 Oct 2024 14:52:44 +0800 Subject: [PATCH 09/13] fix: imports lint --- internal/server/option.go | 3 ++- pkg/streamx/provider/jsonrpc/transport.go | 3 ++- pkg/streamx/provider/ttstream/client_provier.go | 1 + pkg/streamx/provider/ttstream/client_trans_pool.go | 3 ++- pkg/streamx/provider/ttstream/frame_test.go | 1 + pkg/streamx/streamx_common_test.go | 1 + pkg/streamx/streamx_gen_codec_test.go | 4 ++-- pkg/streamx/streamx_user_test.go | 4 ++-- 8 files changed, 13 insertions(+), 7 deletions(-) diff --git a/internal/server/option.go b/internal/server/option.go index ddf0ab82db..5c2a8ffb46 100644 --- a/internal/server/option.go +++ b/internal/server/option.go @@ -23,6 +23,8 @@ import ( "os/signal" "syscall" + "github.com/cloudwego/localsession/backup" + "github.com/cloudwego/kitex/internal/configutil" "github.com/cloudwego/kitex/internal/stream" "github.com/cloudwego/kitex/pkg/acl" @@ -43,7 +45,6 @@ import ( "github.com/cloudwego/kitex/pkg/stats" "github.com/cloudwego/kitex/pkg/transmeta" "github.com/cloudwego/kitex/pkg/utils" - "github.com/cloudwego/localsession/backup" ) func init() { diff --git a/pkg/streamx/provider/jsonrpc/transport.go b/pkg/streamx/provider/jsonrpc/transport.go index e761f89083..399fe3ba9d 100644 --- a/pkg/streamx/provider/jsonrpc/transport.go +++ b/pkg/streamx/provider/jsonrpc/transport.go @@ -24,9 +24,10 @@ import ( "sync" "sync/atomic" + "github.com/cloudwego/netpoll" + "github.com/cloudwego/kitex/pkg/klog" "github.com/cloudwego/kitex/pkg/serviceinfo" - "github.com/cloudwego/netpoll" ) type transport struct { diff --git a/pkg/streamx/provider/ttstream/client_provier.go b/pkg/streamx/provider/ttstream/client_provier.go index 5c82721a5b..f79e760151 100644 --- a/pkg/streamx/provider/ttstream/client_provier.go +++ b/pkg/streamx/provider/ttstream/client_provier.go @@ -23,6 +23,7 @@ import ( "github.com/bytedance/gopkg/cloud/metainfo" "github.com/cloudwego/gopkg/protocol/ttheader" + "github.com/cloudwego/kitex/client/streamxclient/streamxcallopt" "github.com/cloudwego/kitex/pkg/kerrors" "github.com/cloudwego/kitex/pkg/rpcinfo" diff --git a/pkg/streamx/provider/ttstream/client_trans_pool.go b/pkg/streamx/provider/ttstream/client_trans_pool.go index 78be57754d..7ec587d93d 100644 --- a/pkg/streamx/provider/ttstream/client_trans_pool.go +++ b/pkg/streamx/provider/ttstream/client_trans_pool.go @@ -17,8 +17,9 @@ package ttstream import ( - "github.com/cloudwego/kitex/pkg/serviceinfo" "github.com/cloudwego/netpoll" + + "github.com/cloudwego/kitex/pkg/serviceinfo" ) var dialer = netpoll.NewDialer() diff --git a/pkg/streamx/provider/ttstream/frame_test.go b/pkg/streamx/provider/ttstream/frame_test.go index 19283d18c5..6bba79a251 100644 --- a/pkg/streamx/provider/ttstream/frame_test.go +++ b/pkg/streamx/provider/ttstream/frame_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/cloudwego/gopkg/bufiox" + "github.com/cloudwego/kitex/internal/test" ) diff --git a/pkg/streamx/streamx_common_test.go b/pkg/streamx/streamx_common_test.go index aa661d674b..7a154076d4 100644 --- a/pkg/streamx/streamx_common_test.go +++ b/pkg/streamx/streamx_common_test.go @@ -22,6 +22,7 @@ import ( "github.com/bytedance/gopkg/cloud/metainfo" "github.com/cloudwego/gopkg/protocol/thrift" + "github.com/cloudwego/kitex/internal/test" "github.com/cloudwego/kitex/pkg/kerrors" "github.com/cloudwego/kitex/pkg/remote" diff --git a/pkg/streamx/streamx_gen_codec_test.go b/pkg/streamx/streamx_gen_codec_test.go index 129737b04e..67793454aa 100644 --- a/pkg/streamx/streamx_gen_codec_test.go +++ b/pkg/streamx/streamx_gen_codec_test.go @@ -22,9 +22,9 @@ import ( "reflect" "strings" - "github.com/cloudwego/kitex/pkg/protocol/bthrift" - "github.com/apache/thrift/lib/go/thrift" + + "github.com/cloudwego/kitex/pkg/protocol/bthrift" kutils "github.com/cloudwego/kitex/pkg/utils" ) diff --git a/pkg/streamx/streamx_user_test.go b/pkg/streamx/streamx_user_test.go index 089bd89f00..ccc2ee7905 100644 --- a/pkg/streamx/streamx_user_test.go +++ b/pkg/streamx/streamx_user_test.go @@ -29,8 +29,6 @@ import ( "testing" "time" - "github.com/cloudwego/kitex/pkg/streamx" - "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream" "github.com/cloudwego/netpoll" "github.com/cloudwego/kitex/client" @@ -38,6 +36,8 @@ import ( "github.com/cloudwego/kitex/internal/test" "github.com/cloudwego/kitex/pkg/klog" "github.com/cloudwego/kitex/pkg/remote/codec/thrift" + "github.com/cloudwego/kitex/pkg/streamx" + "github.com/cloudwego/kitex/pkg/streamx/provider/ttstream" "github.com/cloudwego/kitex/server" "github.com/cloudwego/kitex/server/streamxserver" "github.com/cloudwego/kitex/transport" From 059c67c5d6471e578bcd41dc1a93da097466e785 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Thu, 17 Oct 2024 15:28:45 +0800 Subject: [PATCH 10/13] chore: rm debug log --- .../provider/ttstream/container/object_pool.go | 15 ++------------- pkg/streamx/streamx_user_test.go | 3 +-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/pkg/streamx/provider/ttstream/container/object_pool.go b/pkg/streamx/provider/ttstream/container/object_pool.go index 28b7f3bb4c..51658e706e 100644 --- a/pkg/streamx/provider/ttstream/container/object_pool.go +++ b/pkg/streamx/provider/ttstream/container/object_pool.go @@ -20,8 +20,6 @@ import ( "sync" "sync/atomic" "time" - - "github.com/cloudwego/kitex/pkg/klog" ) type Object interface { @@ -94,14 +92,9 @@ func (s *ObjectPool) cleaning() { cleanInternal = time.Second * 10 } // clean objects - for key, stk := range s.objects { + for _, stk := range s.objects { deleted := 0 - var oldest *time.Time - klog.Infof("object[%s] pool cleaning %d objects", key, stk.Size()) stk.RangeDelete(func(o objectItem) (deleteNode, continueRange bool) { - if oldest == nil { - oldest = &o.lastActive - } if o.object == nil { deleted++ return true, true @@ -113,13 +106,9 @@ func (s *ObjectPool) cleaning() { return false, false } deleted++ - err := o.object.Close() - klog.Infof("object is invalid: lastActive=%s, closedErr=%v", o.lastActive.String(), err) + _ = o.object.Close() return true, true }) - if oldest != nil { - klog.Infof("object[%s] pool deleted %d objects, oldest=%s", key, deleted, oldest.String()) - } } s.L.Unlock() } diff --git a/pkg/streamx/streamx_user_test.go b/pkg/streamx/streamx_user_test.go index ccc2ee7905..646f8d49b7 100644 --- a/pkg/streamx/streamx_user_test.go +++ b/pkg/streamx/streamx_user_test.go @@ -52,7 +52,7 @@ type testCase struct { } func init() { - klog.SetLevel(klog.LevelDebug) + klog.SetLevel(klog.LevelWarn) sp, _ := ttstream.NewServerProvider(streamingServiceInfo) cp, _ := ttstream.NewClientProvider(streamingServiceInfo, ttstream.WithClientLongConnPool(ttstream.LongConnConfig{MaxIdleTimeout: time.Millisecond * 100})) @@ -538,7 +538,6 @@ func TestStreamingGoroutineLeak(t *testing.T) { test.Assert(t, res.Message == req.Message, res.Message) runtime.SetFinalizer(bs, func(_ any) { wg.Done() - t.Logf("stream is finalized") }) bs = nil runtime.GC() From 4e639ca0867045fe8df34b0e159223d8a62acbd4 Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Thu, 17 Oct 2024 16:41:45 +0800 Subject: [PATCH 11/13] chore: fix server recv/send count --- .github/workflows/tests.yml | 2 +- pkg/remote/trans/streamx/server_handler.go | 2 +- pkg/streamx/streamx_user_test.go | 37 ++++++++++------------ 3 files changed, 18 insertions(+), 23 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1127c83340..9eb99a227b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -48,7 +48,7 @@ jobs: go-version: ${{ matrix.go }} cache: false # don't use cache for self-hosted runners - name: Unit Test - run: go test -race -covermode=atomic ./... + run: go test -v -race -covermode=atomic ./... codegen-test: runs-on: ubuntu-latest diff --git a/pkg/remote/trans/streamx/server_handler.go b/pkg/remote/trans/streamx/server_handler.go index 73490ad261..ede3ec40bb 100644 --- a/pkg/remote/trans/streamx/server_handler.go +++ b/pkg/remote/trans/streamx/server_handler.go @@ -107,7 +107,7 @@ func (t *svrTransHandler) OnRead(ctx context.Context, conn net.Conn) error { streamWorkerPool.GoCtx(ctx, func() { err := t.OnStream(nctx, conn, ss) if err != nil && !errors.Is(err, io.EOF) { - klog.CtxErrorf(ctx, "KITEX: stream ReadStream failed: err=%v", nerr) + klog.CtxErrorf(ctx, "KITEX: stream ReadStream failed: err=%v", err) } }) } diff --git a/pkg/streamx/streamx_user_test.go b/pkg/streamx/streamx_user_test.go index 646f8d49b7..e5e97c2444 100644 --- a/pkg/streamx/streamx_user_test.go +++ b/pkg/streamx/streamx_user_test.go @@ -102,8 +102,6 @@ func TestStreamingBasic(t *testing.T) { err = next(ctx, stream, res) if err == nil { atomic.AddInt32(&serverRecvCount, 1) - } else { - log.Printf("server recv middleware err=%v", err) } return err } @@ -113,8 +111,6 @@ func TestStreamingBasic(t *testing.T) { err = next(ctx, stream, req) if err == nil { atomic.AddInt32(&serverSendCount, 1) - } else { - log.Printf("server send middleware err=%v", err) } return err } @@ -243,12 +239,12 @@ func TestStreamingBasic(t *testing.T) { test.Assert(t, err == nil, err) test.Assert(t, req.Type == res.Type, res.Type) test.Assert(t, req.Message == res.Message, res.Message) - test.Assert(t, serverRecvCount == 1, serverRecvCount) - test.Assert(t, serverSendCount == 1, serverSendCount) atomic.AddInt32(&serverStreamCount, -1) waitServerStreamDone() - serverRecvCount = 0 - serverSendCount = 0 + test.DeepEqual(t, atomic.LoadInt32(&serverRecvCount), int32(1)) + test.DeepEqual(t, atomic.LoadInt32(&serverSendCount), int32(1)) + atomic.StoreInt32(&serverRecvCount, 0) + atomic.StoreInt32(&serverSendCount, 0) // client stream round := 5 @@ -267,12 +263,12 @@ func TestStreamingBasic(t *testing.T) { test.Assert(t, res.Message == "ClientStream", res.Message) atomic.AddInt32(&serverStreamCount, -1) waitServerStreamDone() - test.DeepEqual(t, serverRecvCount, int32(round)) - test.Assert(t, serverSendCount == 1, serverSendCount) testHeaderAndTrailer(t, cs) + test.DeepEqual(t, atomic.LoadInt32(&serverRecvCount), int32(round)) + test.DeepEqual(t, atomic.LoadInt32(&serverSendCount), int32(1)) + atomic.StoreInt32(&serverRecvCount, 0) + atomic.StoreInt32(&serverSendCount, 0) cs = nil - serverRecvCount = 0 - serverSendCount = 0 runtime.GC() // server stream @@ -295,12 +291,12 @@ func TestStreamingBasic(t *testing.T) { test.Assert(t, err == nil, err) atomic.AddInt32(&serverStreamCount, -1) waitServerStreamDone() - test.Assert(t, serverRecvCount == 1, serverRecvCount) - test.Assert(t, serverSendCount == int32(received), serverSendCount, received) testHeaderAndTrailer(t, ss) + test.DeepEqual(t, atomic.LoadInt32(&serverRecvCount), int32(1)) + test.DeepEqual(t, atomic.LoadInt32(&serverSendCount), int32(received)) + atomic.StoreInt32(&serverRecvCount, 0) + atomic.StoreInt32(&serverSendCount, 0) ss = nil - serverRecvCount = 0 - serverSendCount = 0 runtime.GC() // bidi stream @@ -331,7 +327,6 @@ func TestStreamingBasic(t *testing.T) { i := 0 for { res, err := bs.Recv(ctx) - t.Log(res, err) if errors.Is(err, io.EOF) { break } @@ -345,10 +340,10 @@ func TestStreamingBasic(t *testing.T) { }() } waitServerStreamDone() - test.Assert(t, serverRecvCount == int32(concurrent*round), serverRecvCount) - test.Assert(t, serverSendCount == int32(concurrent*round), serverSendCount) - serverRecvCount = 0 - serverSendCount = 0 + test.DeepEqual(t, atomic.LoadInt32(&serverRecvCount), int32(concurrent*round)) + test.DeepEqual(t, atomic.LoadInt32(&serverSendCount), int32(concurrent*round)) + atomic.StoreInt32(&serverRecvCount, 0) + atomic.StoreInt32(&serverSendCount, 0) runtime.GC() t.Logf("=== UnaryWithErr normalErr ===") From 57107421656a078143105f19a2035ddfc82668be Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Thu, 17 Oct 2024 17:15:20 +0800 Subject: [PATCH 12/13] chore: fix stream gc test --- pkg/streamx/streamx_user_test.go | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/pkg/streamx/streamx_user_test.go b/pkg/streamx/streamx_user_test.go index e5e97c2444..5164ffb427 100644 --- a/pkg/streamx/streamx_user_test.go +++ b/pkg/streamx/streamx_user_test.go @@ -486,10 +486,14 @@ func TestStreamingGoroutineLeak(t *testing.T) { // create server svr := server.NewServer(server.WithListener(ln), server.WithExitWaitTime(time.Millisecond*10)) var streamStarted int32 - waitStreamStarted := func(waitStreams int) { - for atomic.LoadInt32(&streamStarted) < int32(waitStreams) { + waitStreamStarted := func(streamWaited int) { + for { + stated, waited := atomic.LoadInt32(&streamStarted), int32(streamWaited) + if stated >= waited { + return + } + t.Logf("streamStarted=%d < streamWaited=%d", stated, waited) time.Sleep(time.Millisecond * 10) - t.Logf("streamStarted=%d < waitStreams=%d", atomic.LoadInt32(&streamStarted), waitStreams) } } _ = svr.RegisterService( @@ -539,10 +543,10 @@ func TestStreamingGoroutineLeak(t *testing.T) { wg.Wait() } - t.Logf("=== Checking Streams GCed ===") - oldNGs := runtime.NumGoroutine() + t.Logf("=== Checking streams GCed ===") streams := 100 streamList := make([]streamx.ServerStream, streams) + ngBefore := runtime.NumGoroutine() atomic.StoreInt32(&streamStarted, 0) for i := 0; i < streams; i++ { ctx := context.Background() @@ -551,18 +555,21 @@ func TestStreamingGoroutineLeak(t *testing.T) { streamList[i] = bs } waitStreamStarted(streams) - ngs := runtime.NumGoroutine() - test.Assert(t, ngs > streams, ngs) + // before GC + test.Assert(t, runtime.NumGoroutine() > streams, runtime.NumGoroutine()) + // after GC for i := 0; i < streams; i++ { streamList[i] = nil } - for ngs-oldNGs > 10 { + // the goroutines diff should < 10 + for runtime.NumGoroutine()-ngBefore > 10 { + t.Logf("ngCurrent=%d > ngBefore=%d", runtime.NumGoroutine(), ngBefore) runtime.GC() - ngs = runtime.NumGoroutine() time.Sleep(time.Millisecond * 50) } t.Logf("=== Checking Streams Called and GCed ===") + ngBefore = runtime.NumGoroutine() streams = 100 for i := 0; i < streams; i++ { wg.Add(1) @@ -586,10 +593,10 @@ func TestStreamingGoroutineLeak(t *testing.T) { }() } wg.Wait() - ngs = runtime.NumGoroutine() - for ngs-oldNGs > 10 { + // the goroutines diff should < 10 + for runtime.NumGoroutine()-ngBefore > 10 { + t.Logf("ngCurrent=%d > ngBefore=%d", runtime.NumGoroutine(), ngBefore) runtime.GC() - ngs = runtime.NumGoroutine() time.Sleep(time.Millisecond * 50) } }) From b6fb816f0fc5b018167f71cb270a52b4de59682d Mon Sep 17 00:00:00 2001 From: Zhuowei Wang Date: Thu, 17 Oct 2024 17:40:51 +0800 Subject: [PATCH 13/13] chore: fix stream gc test --- pkg/streamx/streamx_user_test.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/pkg/streamx/streamx_user_test.go b/pkg/streamx/streamx_user_test.go index 5164ffb427..8d5a1b92ef 100644 --- a/pkg/streamx/streamx_user_test.go +++ b/pkg/streamx/streamx_user_test.go @@ -546,7 +546,6 @@ func TestStreamingGoroutineLeak(t *testing.T) { t.Logf("=== Checking streams GCed ===") streams := 100 streamList := make([]streamx.ServerStream, streams) - ngBefore := runtime.NumGoroutine() atomic.StoreInt32(&streamStarted, 0) for i := 0; i < streams; i++ { ctx := context.Background() @@ -556,20 +555,19 @@ func TestStreamingGoroutineLeak(t *testing.T) { } waitStreamStarted(streams) // before GC + ngBefore := runtime.NumGoroutine() test.Assert(t, runtime.NumGoroutine() > streams, runtime.NumGoroutine()) // after GC for i := 0; i < streams; i++ { streamList[i] = nil } - // the goroutines diff should < 10 - for runtime.NumGoroutine()-ngBefore > 10 { + for runtime.NumGoroutine() > ngBefore { t.Logf("ngCurrent=%d > ngBefore=%d", runtime.NumGoroutine(), ngBefore) runtime.GC() time.Sleep(time.Millisecond * 50) } t.Logf("=== Checking Streams Called and GCed ===") - ngBefore = runtime.NumGoroutine() streams = 100 for i := 0; i < streams; i++ { wg.Add(1) @@ -593,12 +591,6 @@ func TestStreamingGoroutineLeak(t *testing.T) { }() } wg.Wait() - // the goroutines diff should < 10 - for runtime.NumGoroutine()-ngBefore > 10 { - t.Logf("ngCurrent=%d > ngBefore=%d", runtime.NumGoroutine(), ngBefore) - runtime.GC() - time.Sleep(time.Millisecond * 50) - } }) } }