/*
 * Copyright 2021 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 netpollmux

import (
	"context"
	"errors"
	"net"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/cloudwego/netpoll"

	"github.com/cloudwego/kitex/internal/mocks"
	mockmessage "github.com/cloudwego/kitex/internal/mocks/message"
	mocksremote "github.com/cloudwego/kitex/internal/mocks/remote"
	"github.com/cloudwego/kitex/internal/test"
	"github.com/cloudwego/kitex/pkg/remote"
	"github.com/cloudwego/kitex/pkg/remote/codec"
	"github.com/cloudwego/kitex/pkg/rpcinfo"
	"github.com/cloudwego/kitex/pkg/utils"
)

var (
	opt       *remote.ServerOption
	rwTimeout = time.Second
	addrStr   = "test addr"
	addr      = utils.NewNetAddr("tcp", addrStr)
	method    = "mock"

	svcInfo     = mocks.ServiceInfo()
	svcSearcher = mocksremote.NewDefaultSvcSearcher()
)

func newTestRpcInfo() rpcinfo.RPCInfo {
	fromInfo := rpcinfo.EmptyEndpointInfo()
	toInfo := rpcinfo.EmptyEndpointInfo()
	rpcCfg := rpcinfo.NewRPCConfig()
	mCfg := rpcinfo.AsMutableRPCConfig(rpcCfg)
	mCfg.SetReadWriteTimeout(rwTimeout)
	ink := rpcinfo.NewInvocation("", method)
	rpcStat := rpcinfo.NewRPCStats()

	rpcInfo := rpcinfo.NewRPCInfo(fromInfo, toInfo, ink, rpcCfg, rpcStat)
	rpcinfo.AsMutableEndpointInfo(rpcInfo.From()).SetAddress(addr)

	return rpcInfo
}

func init() {
	body := "hello world"
	rpcInfo := newTestRpcInfo()

	opt = &remote.ServerOption{
		InitOrResetRPCInfoFunc: func(ri rpcinfo.RPCInfo, addr net.Addr) rpcinfo.RPCInfo {
			return rpcInfo
		},
		Codec: &MockCodec{
			EncodeFunc: func(ctx context.Context, msg remote.Message, out remote.ByteBuffer) error {
				r := mockHeader(msg.RPCInfo().Invocation().SeqID(), body)
				_, err := out.WriteBinary(r.Bytes())
				return err
			},
			DecodeFunc: func(ctx context.Context, msg remote.Message, in remote.ByteBuffer) error {
				in.Skip(3 * codec.Size32)
				_, err := in.ReadString(len(body))
				if err != nil {
					return err
				}
				msg.RPCInfo().Invocation().(rpcinfo.InvocationSetter).SetServiceName(mocks.MockServiceName)
				return codec.SetOrCheckMethodName(ctx, mocks.MockMethod, msg)
			},
		},
		SvcSearcher:      svcSearcher,
		TracerCtl:        &rpcinfo.TraceController{},
		ReadWriteTimeout: rwTimeout,
	}
}

// TestNewTransHandler test new a ServerTransHandler
func TestNewTransHandler(t *testing.T) {
	handler, err := NewSvrTransHandlerFactory().NewTransHandler(&remote.ServerOption{})
	test.Assert(t, err == nil, err)
	test.Assert(t, handler != nil)
}

// TestOnActive test ServerTransHandler OnActive
func TestOnActive(t *testing.T) {
	// 1. prepare mock data
	var readTimeout time.Duration
	conn := &MockNetpollConn{
		SetReadTimeoutFunc: func(timeout time.Duration) (e error) {
			readTimeout = timeout
			return nil
		},
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
		},
	}

	// 2. test
	ctx := context.Background()

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)

	ctx, err := svrTransHdlr.OnActive(ctx, conn)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)
	muxSvrCon, _ := ctx.Value(ctxKeyMuxSvrConn{}).(*muxSvrConn)
	test.Assert(t, muxSvrCon != nil)
	test.Assert(t, readTimeout == rwTimeout, readTimeout, rwTimeout)
}

// TestMuxSvrWrite test ServerTransHandler Write
func TestMuxSvrWrite(t *testing.T) {
	// 1. prepare mock data
	npconn := &MockNetpollConn{
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
		},
	}
	pool := &sync.Pool{}
	muxSvrCon := newMuxSvrConn(npconn, pool)
	test.Assert(t, muxSvrCon != nil)

	ctx := context.Background()
	rpcInfo := newTestRpcInfo()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	// 2. test
	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err := svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)
}

// TestMuxSvrOnRead test ServerTransHandler OnRead
func TestMuxSvrOnRead(t *testing.T) {
	var isWriteBufFlushed atomic.Value
	var isReaderBufReleased atomic.Value
	var isInvoked atomic.Value

	buf := netpoll.NewLinkBuffer(1024)
	npconn := &MockNetpollConn{
		ReaderFunc: func() (r netpoll.Reader) {
			isReaderBufReleased.Store(1)
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			isWriteBufFlushed.Store(1)
			return buf
		},
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
		},
	}

	ctx := context.Background()
	rpcInfo := newTestRpcInfo()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	pool := &sync.Pool{}
	muxSvrCon := newMuxSvrConn(npconn, pool)

	var err error

	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err = svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	time.Sleep(10 * time.Millisecond)
	buf.Flush()
	test.Assert(t, npconn.Reader().Len() > 0, npconn.Reader().Len())

	ctx, err = svrTransHdlr.OnActive(ctx, muxSvrCon)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)
	muxSvrConFromCtx, _ := ctx.Value(ctxKeyMuxSvrConn{}).(*muxSvrConn)
	test.Assert(t, muxSvrConFromCtx != nil)

	pl := remote.NewTransPipeline(svrTransHdlr)
	svrTransHdlr.SetPipeline(pl)

	if setter, ok := svrTransHdlr.(remote.InvokeHandleFuncSetter); ok {
		setter.SetInvokeHandleFunc(func(ctx context.Context, req, resp interface{}) (err error) {
			isInvoked.Store(1)
			return nil
		})
	}

	err = svrTransHdlr.OnRead(ctx, npconn)
	test.Assert(t, err == nil, err)
	time.Sleep(50 * time.Millisecond)

	test.Assert(t, isReaderBufReleased.Load() == 1)
	test.Assert(t, isWriteBufFlushed.Load() == 1)
	test.Assert(t, isInvoked.Load() == 1)
}

// TestPanicAfterMuxSvrOnRead test have panic after read
func TestPanicAfterMuxSvrOnRead(t *testing.T) {
	// 1. prepare mock data
	var isWriteBufFlushed bool
	var isReaderBufReleased bool

	buf := netpoll.NewLinkBuffer(1024)
	conn := &MockNetpollConn{
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
			CloseFunc: func() (e error) {
				return nil
			},
		},
		ReaderFunc: func() (r netpoll.Reader) {
			isReaderBufReleased = true
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			isWriteBufFlushed = true
			return buf
		},
		IsActiveFunc: func() (r bool) {
			return true
		},
	}

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)
	rpcInfo := newTestRpcInfo()

	// pipeline nil panic
	svrTransHdlr.SetPipeline(nil)

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	pool := &sync.Pool{}
	muxSvrCon := newMuxSvrConn(conn, pool)

	// 2. test
	var err error
	ctx := context.Background()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err = svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	time.Sleep(5 * time.Millisecond)
	buf.Flush()
	test.Assert(t, conn.Reader().Len() > 0, conn.Reader().Len())

	ctx, err = svrTransHdlr.OnActive(ctx, conn)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	err = svrTransHdlr.OnRead(ctx, conn)
	time.Sleep(50 * time.Millisecond)
	test.Assert(t, err == nil, err)
	test.Assert(t, isReaderBufReleased)
	test.Assert(t, isWriteBufFlushed)
}

// TestRecoverAfterOnReadPanic test tryRecover after read panic
func TestRecoverAfterOnReadPanic(t *testing.T) {
	var isWriteBufFlushed bool
	var isReaderBufReleased bool
	var isClosed bool
	buf := netpoll.NewLinkBuffer(1024)

	conn := &MockNetpollConn{
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
			CloseFunc: func() (e error) {
				isClosed = true
				return nil
			},
		},
		ReaderFunc: func() (r netpoll.Reader) {
			isReaderBufReleased = true
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			isWriteBufFlushed = true
			return buf
		},
		IsActiveFunc: func() (r bool) {
			return true
		},
	}

	rpcInfo := newTestRpcInfo()

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	pool := &sync.Pool{}
	muxSvrCon := newMuxSvrConn(conn, pool)

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)

	var err error
	ctx := context.Background()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err = svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	time.Sleep(5 * time.Millisecond)
	buf.Flush()
	test.Assert(t, conn.Reader().Len() > 0, conn.Reader().Len())

	ctx, err = svrTransHdlr.OnActive(ctx, conn)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	// test recover after panic
	err = svrTransHdlr.OnRead(ctx, nil)
	test.Assert(t, err == nil, err)
	test.Assert(t, isReaderBufReleased)
	test.Assert(t, isWriteBufFlushed)
	test.Assert(t, !isClosed)

	// test recover after panic
	err = svrTransHdlr.OnRead(ctx, &MockNetpollConn{})
	test.Assert(t, err == nil, err)
	test.Assert(t, isReaderBufReleased)
	test.Assert(t, isWriteBufFlushed)
	test.Assert(t, !isClosed)
}

// TestOnError test Invoke has err
func TestInvokeError(t *testing.T) {
	var isReaderBufReleased bool
	var isWriteBufFlushed atomic.Value
	var invokedErr atomic.Value

	buf := netpoll.NewLinkBuffer(1024)
	npconn := &MockNetpollConn{
		ReaderFunc: func() (r netpoll.Reader) {
			isReaderBufReleased = true
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			isWriteBufFlushed.Store(1)
			return buf
		},
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
			CloseFunc: func() (e error) {
				return nil
			},
		},
	}

	rpcInfo := newTestRpcInfo()

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	body := "hello world"
	opt := &remote.ServerOption{
		InitOrResetRPCInfoFunc: func(rpcInfo rpcinfo.RPCInfo, addr net.Addr) rpcinfo.RPCInfo {
			fromInfo := rpcinfo.EmptyEndpointInfo()
			toInfo := rpcinfo.EmptyEndpointInfo()
			rpcCfg := rpcinfo.NewRPCConfig()
			mCfg := rpcinfo.AsMutableRPCConfig(rpcCfg)
			mCfg.SetReadWriteTimeout(rwTimeout)
			ink := rpcinfo.NewInvocation("", method)
			rpcStat := rpcinfo.NewRPCStats()
			nri := rpcinfo.NewRPCInfo(fromInfo, toInfo, ink, rpcCfg, rpcStat)
			rpcinfo.AsMutableEndpointInfo(nri.From()).SetAddress(addr)
			return nri
		},
		Codec: &MockCodec{
			EncodeFunc: func(ctx context.Context, msg remote.Message, out remote.ByteBuffer) error {
				r := mockHeader(msg.RPCInfo().Invocation().SeqID(), body)
				_, err := out.WriteBinary(r.Bytes())
				return err
			},
			DecodeFunc: func(ctx context.Context, msg remote.Message, in remote.ByteBuffer) error {
				in.Skip(3 * codec.Size32)
				_, err := in.ReadString(len(body))
				if err != nil {
					return err
				}
				msg.RPCInfo().Invocation().(rpcinfo.InvocationSetter).SetServiceName(mocks.MockServiceName)
				return codec.SetOrCheckMethodName(ctx, mocks.MockMethod, msg)
			},
		},
		SvcSearcher:      svcSearcher,
		TracerCtl:        &rpcinfo.TraceController{},
		ReadWriteTimeout: rwTimeout,
	}

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)

	pool := &sync.Pool{
		New: func() interface{} {
			// init rpcinfo
			ri := opt.InitOrResetRPCInfoFunc(nil, npconn.RemoteAddr())
			return ri
		},
	}
	muxSvrCon := newMuxSvrConn(npconn, pool)

	var err error
	ctx := context.Background()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err = svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	time.Sleep(5 * time.Millisecond)
	buf.Flush()
	test.Assert(t, npconn.Reader().Len() > 0, npconn.Reader().Len())

	ctx, err = svrTransHdlr.OnActive(ctx, muxSvrCon)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)
	muxSvrCon, _ = ctx.Value(ctxKeyMuxSvrConn{}).(*muxSvrConn)
	test.Assert(t, muxSvrCon != nil)

	pl := remote.NewTransPipeline(svrTransHdlr)
	svrTransHdlr.SetPipeline(pl)

	if setter, ok := svrTransHdlr.(remote.InvokeHandleFuncSetter); ok {
		setter.SetInvokeHandleFunc(func(ctx context.Context, req, resp interface{}) (err error) {
			err = errors.New("mock invoke err test")
			invokedErr.Store(err)
			return err
		})
	}

	err = svrTransHdlr.OnRead(ctx, npconn)
	time.Sleep(50 * time.Millisecond)
	test.Assert(t, err == nil, err)
	test.Assert(t, isReaderBufReleased)
	test.Assert(t, invokedErr.Load() != nil)
	test.Assert(t, isWriteBufFlushed.Load() == 1)
}

// TestOnError test OnError method
func TestOnError(t *testing.T) {
	// 1. prepare mock data
	buf := netpoll.NewLinkBuffer(1)
	conn := &MockNetpollConn{
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
			CloseFunc: func() (e error) {
				return nil
			},
		},
		ReaderFunc: func() (r netpoll.Reader) {
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			return buf
		},
	}

	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(opt)

	// 2. test
	ctx := context.Background()
	rpcInfo := newTestRpcInfo()

	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)
	svrTransHdlr.OnError(ctx, errors.New("test mock err"), conn)
	svrTransHdlr.OnError(ctx, netpoll.ErrConnClosed, conn)
}

// TestInvokeNoMethod test invoke no method
func TestInvokeNoMethod(t *testing.T) {
	var isWriteBufFlushed atomic.Value
	var isReaderBufReleased bool
	var isInvoked bool

	buf := netpoll.NewLinkBuffer(1024)
	npconn := &MockNetpollConn{
		ReaderFunc: func() (r netpoll.Reader) {
			isReaderBufReleased = true
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			isWriteBufFlushed.Store(1)
			return buf
		},
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
			CloseFunc: func() (e error) {
				return nil
			},
		},
	}

	rpcInfo := newTestRpcInfo()

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	body := "hello world"
	svrOpt := &remote.ServerOption{
		InitOrResetRPCInfoFunc: func(ri rpcinfo.RPCInfo, addr net.Addr) rpcinfo.RPCInfo {
			return rpcInfo
		},
		Codec: &MockCodec{
			EncodeFunc: func(ctx context.Context, msg remote.Message, out remote.ByteBuffer) error {
				r := mockHeader(msg.RPCInfo().Invocation().SeqID(), body)
				_, err := out.WriteBinary(r.Bytes())
				return err
			},
			DecodeFunc: func(ctx context.Context, msg remote.Message, in remote.ByteBuffer) error {
				in.Skip(3 * codec.Size32)
				_, err := in.ReadString(len(body))
				if err != nil {
					return err
				}
				return remote.NewTransError(remote.UnknownMethod, errors.New("unknown method"))
			},
		},
		SvcSearcher: svcSearcher,
		TracerCtl:   &rpcinfo.TraceController{},
	}
	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(svrOpt)

	pool := &sync.Pool{}
	muxSvrCon := newMuxSvrConn(npconn, pool)

	var err error
	ctx := context.Background()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err = svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	time.Sleep(5 * time.Millisecond)
	buf.Flush()
	test.Assert(t, npconn.Reader().Len() > 0, npconn.Reader().Len())

	ctx, err = svrTransHdlr.OnActive(ctx, muxSvrCon)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)
	muxSvrCon, _ = ctx.Value(ctxKeyMuxSvrConn{}).(*muxSvrConn)
	test.Assert(t, muxSvrCon != nil)

	pl := remote.NewTransPipeline(svrTransHdlr)
	svrTransHdlr.SetPipeline(pl)

	if setter, ok := svrTransHdlr.(remote.InvokeHandleFuncSetter); ok {
		setter.SetInvokeHandleFunc(func(ctx context.Context, req, resp interface{}) (err error) {
			isInvoked = true
			return nil
		})
	}

	err = svrTransHdlr.OnRead(ctx, npconn)
	time.Sleep(50 * time.Millisecond)
	test.Assert(t, err == nil, err)
	test.Assert(t, isReaderBufReleased)
	test.Assert(t, isWriteBufFlushed.Load() == 1)
	test.Assert(t, !isInvoked)
}

// TestMuxSvcOnReadHeartbeat test SvrTransHandler OnRead to process heartbeat
func TestMuxSvrOnReadHeartbeat(t *testing.T) {
	var isWriteBufFlushed atomic.Value
	var isReaderBufReleased atomic.Value
	var isInvoked atomic.Value

	buf := netpoll.NewLinkBuffer(1024)
	npconn := &MockNetpollConn{
		ReaderFunc: func() (r netpoll.Reader) {
			isReaderBufReleased.Store(1)
			return buf
		},
		WriterFunc: func() (r netpoll.Writer) {
			isWriteBufFlushed.Store(1)
			return buf
		},
		Conn: mocks.Conn{
			RemoteAddrFunc: func() (r net.Addr) {
				return addr
			},
		},
	}

	var heartbeatFlag bool
	body := "non-heartbeat process"
	ctx := context.Background()
	rpcInfo := newTestRpcInfo()
	ctx = rpcinfo.NewCtxWithRPCInfo(ctx, rpcInfo)

	// use newOpt cause we need to add heartbeat logic to EncodeFunc and DecodeFunc
	newOpt := &remote.ServerOption{
		InitOrResetRPCInfoFunc: func(ri rpcinfo.RPCInfo, addr net.Addr) rpcinfo.RPCInfo {
			return rpcInfo
		},
		Codec: &MockCodec{
			EncodeFunc: func(ctx context.Context, msg remote.Message, out remote.ByteBuffer) error {
				if heartbeatFlag {
					if msg.MessageType() != remote.Heartbeat {
						return errors.New("response is not of MessageType Heartbeat")
					}
					return nil
				}
				r := mockHeader(msg.RPCInfo().Invocation().SeqID(), body)
				_, err := out.WriteBinary(r.Bytes())
				return err
			},
			DecodeFunc: func(ctx context.Context, msg remote.Message, in remote.ByteBuffer) error {
				if heartbeatFlag {
					msg.SetMessageType(remote.Heartbeat)
					return nil
				}
				in.Skip(3 * codec.Size32)
				_, err := in.ReadString(len(body))
				return err
			},
		},
		SvcSearcher:      svcSearcher,
		TracerCtl:        &rpcinfo.TraceController{},
		ReadWriteTimeout: rwTimeout,
	}
	svrTransHdlr, _ := NewSvrTransHandlerFactory().NewTransHandler(newOpt)

	msg := &mockmessage.MockMessage{
		RPCInfoFunc: func() rpcinfo.RPCInfo {
			return rpcInfo
		},
	}

	pool := &sync.Pool{}
	muxSvrCon := newMuxSvrConn(npconn, pool)

	var err error

	ri := rpcinfo.GetRPCInfo(ctx)
	test.Assert(t, ri != nil, ri)

	ctx, err = svrTransHdlr.Write(ctx, muxSvrCon, msg)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)

	time.Sleep(10 * time.Millisecond)
	buf.Flush()
	test.Assert(t, npconn.Reader().Len() > 0, npconn.Reader().Len())

	ctx, err = svrTransHdlr.OnActive(ctx, muxSvrCon)
	test.Assert(t, ctx != nil, ctx)
	test.Assert(t, err == nil, err)
	muxSvrConFromCtx, _ := ctx.Value(ctxKeyMuxSvrConn{}).(*muxSvrConn)
	test.Assert(t, muxSvrConFromCtx != nil)

	pl := remote.NewTransPipeline(svrTransHdlr)
	svrTransHdlr.SetPipeline(pl)

	if setter, ok := svrTransHdlr.(remote.InvokeHandleFuncSetter); ok {
		setter.SetInvokeHandleFunc(func(ctx context.Context, req, resp interface{}) (err error) {
			isInvoked.Store(1)
			return nil
		})
	}

	// start the heartbeat processing
	heartbeatFlag = true
	err = svrTransHdlr.OnRead(ctx, npconn)
	test.Assert(t, err == nil, err)
	time.Sleep(50 * time.Millisecond)

	test.Assert(t, isReaderBufReleased.Load() == 1)
	test.Assert(t, isWriteBufFlushed.Load() == 1)
	// InvokeHandleFunc has not been invoked
	test.Assert(t, isInvoked.Load() == nil)
}
