github.com/MontFerret/ferret@v0.18.0/pkg/drivers/cdp/events/stream_test.go (about) 1 package events_test 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/mafredri/cdp/rpcc" 9 "github.com/pkg/errors" 10 "github.com/stretchr/testify/mock" 11 12 events2 "github.com/MontFerret/ferret/pkg/drivers/cdp/events" 13 "github.com/MontFerret/ferret/pkg/runtime/core" 14 "github.com/MontFerret/ferret/pkg/runtime/events" 15 "github.com/MontFerret/ferret/pkg/runtime/values" 16 17 . "github.com/smartystreets/goconvey/convey" 18 ) 19 20 type ( 21 TestStream struct { 22 mock.Mock 23 ready chan struct{} 24 message chan events.Message 25 } 26 ) 27 28 func NewTestStream() *TestStream { 29 return NewBufferedTestStream(0) 30 } 31 32 func NewBufferedTestStream(buffer int) *TestStream { 33 es := new(TestStream) 34 es.ready = make(chan struct{}, buffer) 35 es.message = make(chan events.Message, buffer) 36 return es 37 } 38 39 func (ts *TestStream) Ready() <-chan struct{} { 40 return ts.ready 41 } 42 43 func (ts *TestStream) RecvMsg(m interface{}) error { 44 return nil 45 } 46 47 func (ts *TestStream) Close() error { 48 ts.Called() 49 close(ts.message) 50 close(ts.ready) 51 return nil 52 } 53 54 func (ts *TestStream) Emit(val core.Value) { 55 ts.ready <- struct{}{} 56 ts.message <- events.WithValue(val) 57 } 58 59 func (ts *TestStream) EmitError(err error) { 60 ts.ready <- struct{}{} 61 ts.message <- events.WithErr(err) 62 } 63 64 func (ts *TestStream) Recv() (core.Value, error) { 65 msg := <-ts.message 66 67 return msg.Value(), msg.Err() 68 } 69 70 func TestStreamReader(t *testing.T) { 71 Convey("StreamReader", t, func() { 72 Convey("Should read data from Stream", func() { 73 ctx, cancel := context.WithCancel(context.Background()) 74 75 stream := NewTestStream() 76 stream.On("Close", mock.Anything).Maybe().Return(nil) 77 78 go func() { 79 stream.Emit(values.NewString("foo")) 80 stream.Emit(values.NewString("bar")) 81 stream.Emit(values.NewString("baz")) 82 cancel() 83 }() 84 85 data := make([]string, 0, 3) 86 87 es := events2.NewEventStream(stream, func(_ context.Context, stream rpcc.Stream) (core.Value, error) { 88 return stream.(*TestStream).Recv() 89 }) 90 91 for evt := range es.Read(ctx) { 92 So(evt.Err(), ShouldBeNil) 93 So(evt.Value(), ShouldNotBeNil) 94 95 data = append(data, evt.Value().String()) 96 } 97 98 So(data, ShouldResemble, []string{"foo", "bar", "baz"}) 99 100 stream.AssertExpectations(t) 101 102 So(es.Close(context.Background()), ShouldBeNil) 103 }) 104 105 Convey("Should handle error but do not close Stream", func() { 106 ctx := context.Background() 107 108 stream := NewTestStream() 109 stream.On("Close", mock.Anything).Maybe().Return(nil) 110 111 go func() { 112 stream.EmitError(errors.New("foo")) 113 }() 114 115 reader := events2.NewEventStream(stream, func(_ context.Context, stream rpcc.Stream) (core.Value, error) { 116 return stream.(*TestStream).Recv() 117 }) 118 119 ch := reader.Read(ctx) 120 evt := <-ch 121 So(evt.Err(), ShouldNotBeNil) 122 123 time.Sleep(time.Duration(100) * time.Millisecond) 124 125 stream.AssertExpectations(t) 126 }) 127 128 Convey("Should not close Stream when Context is cancelled", func() { 129 stream := NewTestStream() 130 stream.On("Close", mock.Anything).Maybe().Return(nil) 131 132 reader := events2.NewEventStream(stream, func(_ context.Context, stream rpcc.Stream) (core.Value, error) { 133 return values.EmptyArray(), nil 134 }) 135 136 ctx, cancel := context.WithCancel(context.Background()) 137 138 _ = reader.Read(ctx) 139 140 time.Sleep(time.Duration(100) * time.Millisecond) 141 142 cancel() 143 144 time.Sleep(time.Duration(100) * time.Millisecond) 145 146 stream.AssertExpectations(t) 147 }) 148 }) 149 }