diff --git a/pkg/app2/manager.go b/pkg/app2/id_manager.go similarity index 97% rename from pkg/app2/manager.go rename to pkg/app2/id_manager.go index ffb6ebbfcf..771d7f9ea7 100644 --- a/pkg/app2/manager.go +++ b/pkg/app2/id_manager.go @@ -97,5 +97,8 @@ func (m *idManager) get(key uint16) (interface{}, bool) { m.mx.RLock() lis, ok := m.values[key] m.mx.RUnlock() + if lis == nil { + return nil, false + } return lis, ok } diff --git a/pkg/app2/manager_test.go b/pkg/app2/id_manager_test.go similarity index 100% rename from pkg/app2/manager_test.go rename to pkg/app2/id_manager_test.go diff --git a/pkg/app2/network/dmsg_conn.go b/pkg/app2/network/dmsg_conn.go index 9c6e8220bc..c653f8d5d1 100644 --- a/pkg/app2/network/dmsg_conn.go +++ b/pkg/app2/network/dmsg_conn.go @@ -13,6 +13,10 @@ type DMSGConn struct { tp *dmsg.Transport } +func NewDMSGConn(tp *dmsg.Transport) *DMSGConn { + return &DMSGConn{tp: tp} +} + func (c *DMSGConn) Read(b []byte) (n int, err error) { return c.tp.Read(b) } diff --git a/pkg/app2/network/dmsg_networker.go b/pkg/app2/network/dmsg_networker.go index d772260df4..0cdffbb632 100644 --- a/pkg/app2/network/dmsg_networker.go +++ b/pkg/app2/network/dmsg_networker.go @@ -31,7 +31,7 @@ func (n *DMSGNetworker) DialContext(ctx context.Context, addr Addr) (net.Conn, e return nil, err } - return &DMSGConn{tp: tp}, nil + return NewDMSGConn(tp), nil } // Listen starts listening on local `addr` in the dmsg network. diff --git a/pkg/app2/rpc_gateway.go b/pkg/app2/rpc_gateway.go index a84652105c..bb868399e9 100644 --- a/pkg/app2/rpc_gateway.go +++ b/pkg/app2/rpc_gateway.go @@ -112,10 +112,8 @@ func (r *RPCGateway) Accept(lisID *uint16, resp *AcceptResp) error { return errors.New("wrong type for remote addr") } - resp = &AcceptResp{ - Remote: remote, - ConnID: *connID, - } + resp.Remote = remote + resp.ConnID = *connID return nil } @@ -197,7 +195,7 @@ func (r *RPCGateway) CloseListener(lisID *uint16, _ *struct{}) error { func (r *RPCGateway) popListener(lisID uint16) (net.Listener, error) { lisIfc, err := r.lm.pop(lisID) if err != nil { - return nil, err + return nil, errors.Wrap(err, "no listener") } return r.assertListener(lisIfc) @@ -208,7 +206,7 @@ func (r *RPCGateway) popListener(lisID uint16) (net.Listener, error) { func (r *RPCGateway) popConn(connID uint16) (net.Conn, error) { connIfc, err := r.cm.pop(connID) if err != nil { - return nil, err + return nil, errors.Wrap(err, "no conn") } return r.assertConn(connIfc) diff --git a/pkg/app2/rpc_gateway_test.go b/pkg/app2/rpc_gateway_test.go index d230ed120a..9e5301f231 100644 --- a/pkg/app2/rpc_gateway_test.go +++ b/pkg/app2/rpc_gateway_test.go @@ -4,6 +4,7 @@ import ( "context" "math" "net" + "strings" "testing" "github.com/pkg/errors" @@ -148,23 +149,367 @@ func TestRPCGateway_Listen(t *testing.T) { func TestRPCGateway_Accept(t *testing.T) { l := logging.MustGetLogger("rpc_gateway") - rpc := newRPCGateway(l) + t.Run("ok", func(t *testing.T) { + rpc := newRPCGateway(l) - lisID, err := rpc.lm.nextKey() - require.NoError(t, err) + acceptConn := network.NewDMSGConn(&dmsg.Transport{}) + var acceptErr error - acceptConn := &dmsg.Transport{} - var acceptErr error + lis := &MockListener{} + lis.On("Accept").Return(acceptConn, acceptErr) - lis := &MockListener{} - lis.On("Accept").Return(acceptConn, acceptErr) + lisID := addListener(t, rpc, lis) - err = rpc.lm.set(*lisID, lis) - require.NoError(t, err) + var resp AcceptResp + err := rpc.Accept(&lisID, &resp) + require.NoError(t, err) + require.Equal(t, resp.Remote, acceptConn.RemoteAddr()) + }) - var resp AcceptResp - err = rpc.Accept(lisID, &resp) - require.NoError(t, err) + t.Run("no such listener", func(t *testing.T) { + rpc := newRPCGateway(l) + + lisID := uint16(1) + + var resp AcceptResp + err := rpc.Accept(&lisID, &resp) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no listener")) + }) + + t.Run("listener is not set", func(t *testing.T) { + rpc := newRPCGateway(l) + + lisID := addListener(t, rpc, nil) + + var resp AcceptResp + err := rpc.Accept(&lisID, &resp) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no listener")) + }) + + t.Run("no more slots for a new conn", func(t *testing.T) { + rpc := newRPCGateway(l) + for i := uint16(0); i < math.MaxUint16; i++ { + rpc.cm.values[i] = nil + } + rpc.cm.values[math.MaxUint16] = nil + + lisID := addListener(t, rpc, &MockListener{}) + + var resp AcceptResp + err := rpc.Accept(&lisID, &resp) + require.Equal(t, err, errNoMoreAvailableValues) + }) + + t.Run("accept error", func(t *testing.T) { + rpc := newRPCGateway(l) + + var acceptConn net.Conn + acceptErr := errors.New("accept error") + + lis := &MockListener{} + lis.On("Accept").Return(acceptConn, acceptErr) + + lisID := addListener(t, rpc, lis) + + var resp AcceptResp + err := rpc.Accept(&lisID, &resp) + require.Equal(t, err, acceptErr) + }) + + t.Run("wrong type of remote addr", func(t *testing.T) { + rpc := newRPCGateway(l) + + acceptConn := &dmsg.Transport{} + var acceptErr error + + lis := &MockListener{} + lis.On("Accept").Return(acceptConn, acceptErr) + + lisID := addListener(t, rpc, lis) + + var resp AcceptResp + err := rpc.Accept(&lisID, &resp) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "wrong type")) + }) +} + +func TestRPCGateway_Write(t *testing.T) { + l := logging.MustGetLogger("rpc_gateway") + + writeBuff := []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1} + writeN := 10 + + t.Run("ok", func(t *testing.T) { + rpc := newRPCGateway(l) + + var writeErr error + + conn := &MockConn{} + conn.On("Write", writeBuff).Return(writeN, writeErr) + + connID := addConn(t, rpc, conn) + + req := WriteReq{ + ConnID: connID, + B: writeBuff, + } + + var n int + err := rpc.Write(&req, &n) + require.NoError(t, err) + require.Equal(t, n, writeN) + }) + + t.Run("no such conn", func(t *testing.T) { + rpc := newRPCGateway(l) + + connID := uint16(1) + + req := WriteReq{ + ConnID: connID, + B: writeBuff, + } + + var n int + err := rpc.Write(&req, &n) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no conn")) + }) + + t.Run("conn is not set", func(t *testing.T) { + rpc := newRPCGateway(l) + + connID := addConn(t, rpc, nil) + + req := WriteReq{ + ConnID: connID, + B: writeBuff, + } + + var n int + err := rpc.Write(&req, &n) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no conn")) + }) + + t.Run("write error", func(t *testing.T) { + rpc := newRPCGateway(l) + + writeErr := errors.New("write error") + + conn := &MockConn{} + conn.On("Write", writeBuff).Return(writeN, writeErr) + + connID := addConn(t, rpc, conn) + + req := WriteReq{ + ConnID: connID, + B: writeBuff, + } + + var n int + err := rpc.Write(&req, &n) + require.Error(t, err) + require.Equal(t, err, writeErr) + }) +} + +func TestRPCGateway_Read(t *testing.T) { + l := logging.MustGetLogger("rpc_gateway") + + readBufLen := 10 + readBuf := make([]byte, readBufLen) + + t.Run("ok", func(t *testing.T) { + rpc := newRPCGateway(l) + + readN := 10 + var readErr error + + conn := &MockConn{} + conn.On("Read", readBuf).Return(readN, readErr) + + connID := addConn(t, rpc, conn) + + req := ReadReq{ + ConnID: connID, + BufLen: readBufLen, + } + + wantResp := ReadResp{ + B: readBuf, + N: readN, + } + + var resp ReadResp + err := rpc.Read(&req, &resp) + require.NoError(t, err) + require.Equal(t, resp, wantResp) + }) + + t.Run("no such conn", func(t *testing.T) { + rpc := newRPCGateway(l) + + connID := uint16(1) + + req := ReadReq{ + ConnID: connID, + BufLen: readBufLen, + } + + var resp ReadResp + err := rpc.Read(&req, &resp) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no conn")) + }) + + t.Run("conn is not set", func(t *testing.T) { + rpc := newRPCGateway(l) + + connID := addConn(t, rpc, nil) + + req := ReadReq{ + ConnID: connID, + BufLen: readBufLen, + } + + var resp ReadResp + err := rpc.Read(&req, &resp) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no conn")) + }) + + t.Run("read error", func(t *testing.T) { + rpc := newRPCGateway(l) + + readN := 0 + readErr := errors.New("read error") + + conn := &MockConn{} + conn.On("Read", readBuf).Return(readN, readErr) + + connID := addConn(t, rpc, conn) + + req := ReadReq{ + ConnID: connID, + BufLen: readBufLen, + } + + var resp ReadResp + err := rpc.Read(&req, &resp) + require.Equal(t, err, readErr) + }) +} + +func TestRPCGateway_CloseConn(t *testing.T) { + l := logging.MustGetLogger("rpc_gateway") + + t.Run("ok", func(t *testing.T) { + rpc := newRPCGateway(l) + + var closeErr error + + conn := &MockConn{} + conn.On("Close").Return(closeErr) + + connID := addConn(t, rpc, conn) + + err := rpc.CloseConn(&connID, nil) + require.NoError(t, err) + _, ok := rpc.cm.values[connID] + require.False(t, ok) + }) + + t.Run("no such conn", func(t *testing.T) { + rpc := newRPCGateway(l) + + connID := uint16(1) + + err := rpc.CloseConn(&connID, nil) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no conn")) + }) + + t.Run("conn is not set", func(t *testing.T) { + rpc := newRPCGateway(l) + + connID := addConn(t, rpc, nil) + + err := rpc.CloseConn(&connID, nil) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no conn")) + }) + + t.Run("close error", func(t *testing.T) { + rpc := newRPCGateway(l) + + closeErr := errors.New("close error") + + conn := &MockConn{} + conn.On("Close").Return(closeErr) + + connID := addConn(t, rpc, conn) + + err := rpc.CloseConn(&connID, nil) + require.Equal(t, err, closeErr) + }) +} + +func TestRPCGateway_CloseListener(t *testing.T) { + l := logging.MustGetLogger("rpc_gateway") + + t.Run("ok", func(t *testing.T) { + rpc := newRPCGateway(l) + + var closeErr error + + lis := &MockListener{} + lis.On("Close").Return(closeErr) + + lisID := addListener(t, rpc, lis) + + err := rpc.CloseListener(&lisID, nil) + require.NoError(t, err) + _, ok := rpc.lm.values[lisID] + require.False(t, ok) + }) + + t.Run("no such listener", func(t *testing.T) { + rpc := newRPCGateway(l) + + lisID := uint16(1) + + err := rpc.CloseListener(&lisID, nil) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no listener")) + }) + + t.Run("listener is not set", func(t *testing.T) { + rpc := newRPCGateway(l) + + lisID := addListener(t, rpc, nil) + + err := rpc.CloseListener(&lisID, nil) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "no listener")) + }) + + t.Run("close error", func(t *testing.T) { + rpc := newRPCGateway(l) + + closeErr := errors.New("close error") + + lis := &MockListener{} + lis.On("Close").Return(closeErr) + + lisID := addListener(t, rpc, lis) + + err := rpc.CloseListener(&lisID, nil) + require.Equal(t, err, closeErr) + }) } func prepAddr(nType network.Type) network.Addr { @@ -177,3 +522,23 @@ func prepAddr(nType network.Type) network.Addr { Port: port, } } + +func addConn(t *testing.T, rpc *RPCGateway, conn net.Conn) uint16 { + connID, err := rpc.cm.nextKey() + require.NoError(t, err) + + err = rpc.cm.set(*connID, conn) + require.NoError(t, err) + + return *connID +} + +func addListener(t *testing.T, rpc *RPCGateway, lis net.Listener) uint16 { + lisID, err := rpc.lm.nextKey() + require.NoError(t, err) + + err = rpc.lm.set(*lisID, lis) + require.NoError(t, err) + + return *lisID +} diff --git a/vendor/github.com/skycoin/dmsg/go.mod b/vendor/github.com/skycoin/dmsg/go.mod index 1ef2c47f66..a24455c1f5 100644 --- a/vendor/github.com/skycoin/dmsg/go.mod +++ b/vendor/github.com/skycoin/dmsg/go.mod @@ -14,7 +14,7 @@ require ( golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 // indirect golang.org/x/net v0.0.0-20190620200207-3b0461eec859 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect + golang.org/x/text v0.3.2 // indirect + golang.org/x/tools v0.0.0-20190627182818-9947fec5c3ab // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) - -replace github.com/skycoin/dmsg => ../dmsg diff --git a/vendor/github.com/skycoin/dmsg/go.sum b/vendor/github.com/skycoin/dmsg/go.sum index 624818fed7..c6a730a9e6 100644 --- a/vendor/github.com/skycoin/dmsg/go.sum +++ b/vendor/github.com/skycoin/dmsg/go.sum @@ -32,9 +32,11 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -43,5 +45,9 @@ golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSF golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190627182818-9947fec5c3ab h1:uOzhX2fm3C4BmBwW2a7lnJQD7qel2+4uhmTc8czKBCU= +golang.org/x/tools v0.0.0-20190627182818-9947fec5c3ab/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=