You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

221 lines
5.1 KiB

package p2p
import (
"context"
"errors"
"testing"
"time"
"github.com/fortytw2/leaktest"
"github.com/stretchr/testify/require"
)
type channelInternal struct {
In chan Envelope
Out chan Envelope
Error chan PeerError
}
func testChannel(size int) (*channelInternal, *Channel) {
in := &channelInternal{
In: make(chan Envelope, size),
Out: make(chan Envelope, size),
Error: make(chan PeerError, size),
}
ch := &Channel{
In: in.In,
Out: in.Out,
errCh: in.Error,
}
return in, ch
}
func TestChannel(t *testing.T) {
t.Cleanup(leaktest.Check(t))
bctx, bcancel := context.WithCancel(context.Background())
defer bcancel()
testCases := []struct {
Name string
Case func(context.Context, *testing.T)
}{
{
Name: "Send",
Case: func(ctx context.Context, t *testing.T) {
ins, ch := testChannel(1)
require.NoError(t, ch.Send(ctx, Envelope{From: "kip", To: "merlin"}))
res, ok := <-ins.Out
require.True(t, ok)
require.EqualValues(t, "kip", res.From)
require.EqualValues(t, "merlin", res.To)
},
},
{
Name: "SendError",
Case: func(ctx context.Context, t *testing.T) {
ins, ch := testChannel(1)
require.NoError(t, ch.SendError(ctx, PeerError{NodeID: "kip", Err: errors.New("merlin")}))
res, ok := <-ins.Error
require.True(t, ok)
require.EqualValues(t, "kip", res.NodeID)
require.EqualValues(t, "merlin", res.Err.Error())
},
},
{
Name: "SendWithCanceledContext",
Case: func(ctx context.Context, t *testing.T) {
_, ch := testChannel(0)
cctx, ccancel := context.WithCancel(ctx)
ccancel()
require.Error(t, ch.Send(cctx, Envelope{From: "kip", To: "merlin"}))
},
},
{
Name: "SendErrorWithCanceledContext",
Case: func(ctx context.Context, t *testing.T) {
_, ch := testChannel(0)
cctx, ccancel := context.WithCancel(ctx)
ccancel()
require.Error(t, ch.SendError(cctx, PeerError{NodeID: "kip", Err: errors.New("merlin")}))
},
},
{
Name: "ReceiveEmptyIteratorBlocks",
Case: func(ctx context.Context, t *testing.T) {
_, ch := testChannel(1)
iter := ch.Receive(ctx)
require.NotNil(t, iter)
out := make(chan bool)
go func() {
defer close(out)
select {
case <-ctx.Done():
case out <- iter.Next(ctx):
}
}()
select {
case <-time.After(10 * time.Millisecond):
case <-out:
require.Fail(t, "iterator should not advance")
}
require.Nil(t, iter.Envelope())
},
},
{
Name: "ReceiveWithData",
Case: func(ctx context.Context, t *testing.T) {
ins, ch := testChannel(1)
ins.In <- Envelope{From: "kip", To: "merlin"}
iter := ch.Receive(ctx)
require.NotNil(t, iter)
require.True(t, iter.Next(ctx))
res := iter.Envelope()
require.EqualValues(t, "kip", res.From)
require.EqualValues(t, "merlin", res.To)
},
},
{
Name: "ReceiveWithCanceledContext",
Case: func(ctx context.Context, t *testing.T) {
_, ch := testChannel(0)
cctx, ccancel := context.WithCancel(ctx)
ccancel()
iter := ch.Receive(cctx)
require.NotNil(t, iter)
require.False(t, iter.Next(cctx))
require.Nil(t, iter.Envelope())
},
},
{
Name: "IteratorWithCanceledContext",
Case: func(ctx context.Context, t *testing.T) {
_, ch := testChannel(0)
iter := ch.Receive(ctx)
require.NotNil(t, iter)
cctx, ccancel := context.WithCancel(ctx)
ccancel()
require.False(t, iter.Next(cctx))
require.Nil(t, iter.Envelope())
},
},
{
Name: "IteratorCanceledAfterFirstUseBecomesNil",
Case: func(ctx context.Context, t *testing.T) {
ins, ch := testChannel(1)
ins.In <- Envelope{From: "kip", To: "merlin"}
iter := ch.Receive(ctx)
require.NotNil(t, iter)
require.True(t, iter.Next(ctx))
res := iter.Envelope()
require.EqualValues(t, "kip", res.From)
require.EqualValues(t, "merlin", res.To)
cctx, ccancel := context.WithCancel(ctx)
ccancel()
require.False(t, iter.Next(cctx))
require.Nil(t, iter.Envelope())
},
},
{
Name: "IteratorMultipleNextCalls",
Case: func(ctx context.Context, t *testing.T) {
ins, ch := testChannel(1)
ins.In <- Envelope{From: "kip", To: "merlin"}
iter := ch.Receive(ctx)
require.NotNil(t, iter)
require.True(t, iter.Next(ctx))
res := iter.Envelope()
require.EqualValues(t, "kip", res.From)
require.EqualValues(t, "merlin", res.To)
res1 := iter.Envelope()
require.Equal(t, res, res1)
},
},
{
Name: "IteratorProducesNilObjectBeforeNext",
Case: func(ctx context.Context, t *testing.T) {
ins, ch := testChannel(1)
iter := ch.Receive(ctx)
require.NotNil(t, iter)
require.Nil(t, iter.Envelope())
ins.In <- Envelope{From: "kip", To: "merlin"}
require.NotNil(t, iter)
require.True(t, iter.Next(ctx))
res := iter.Envelope()
require.NotNil(t, res)
require.EqualValues(t, "kip", res.From)
require.EqualValues(t, "merlin", res.To)
},
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
t.Cleanup(leaktest.Check(t))
ctx, cancel := context.WithCancel(bctx)
defer cancel()
tc.Case(ctx, t)
})
}
}