github.com/MontFerret/ferret@v0.18.0/pkg/drivers/cdp/events/loop_test.go (about) 1 package events_test 2 3 import ( 4 "context" 5 "sync" 6 "sync/atomic" 7 "testing" 8 "time" 9 10 "github.com/mafredri/cdp/rpcc" 11 . "github.com/smartystreets/goconvey/convey" 12 13 "github.com/MontFerret/ferret/pkg/drivers/cdp/events" 14 ) 15 16 type TestEventStream struct { 17 closed atomic.Value 18 ready chan struct{} 19 messages chan string 20 } 21 22 var TestEvent = events.New("test_event") 23 24 func NewTestEventStream() *TestEventStream { 25 return NewBufferedTestEventStream(0) 26 } 27 28 func NewBufferedTestEventStream(buffer int) *TestEventStream { 29 es := new(TestEventStream) 30 es.ready = make(chan struct{}, buffer) 31 es.messages = make(chan string, buffer) 32 es.closed.Store(false) 33 34 return es 35 } 36 37 func (es *TestEventStream) IsClosed() bool { 38 return es.closed.Load().(bool) 39 } 40 41 func (es *TestEventStream) Ready() <-chan struct{} { 42 return es.ready 43 } 44 45 func (es *TestEventStream) RecvMsg(i interface{}) error { 46 // NOT IMPLEMENTED 47 return nil 48 } 49 50 func (es *TestEventStream) Recv() (interface{}, error) { 51 msg := <-es.messages 52 53 return msg, nil 54 } 55 56 func (es *TestEventStream) Close() error { 57 es.closed.Store(true) 58 close(es.messages) 59 close(es.ready) 60 return nil 61 } 62 63 func (es *TestEventStream) EmitP(msg string, skipCheck bool) { 64 if !skipCheck { 65 isClosed := es.closed.Load().(bool) 66 67 if isClosed { 68 return 69 } 70 } 71 72 es.ready <- struct{}{} 73 es.messages <- msg 74 } 75 76 func (es *TestEventStream) Emit(msg string) { 77 es.EmitP(msg, false) 78 } 79 80 func (es *TestEventStream) EmitDefault() { 81 es.Emit("") 82 } 83 84 func wait() { 85 time.Sleep(time.Duration(50) * time.Millisecond) 86 } 87 88 type Counter struct { 89 mu sync.Mutex 90 value int64 91 } 92 93 func NewCounter() *Counter { 94 return new(Counter) 95 } 96 97 func (c *Counter) Increase() *Counter { 98 c.mu.Lock() 99 defer c.mu.Unlock() 100 101 c.value++ 102 103 return c 104 } 105 106 func (c *Counter) Decrease() *Counter { 107 c.mu.Lock() 108 defer c.mu.Unlock() 109 110 c.value-- 111 112 return c 113 } 114 115 func (c *Counter) Value() int64 { 116 c.mu.Lock() 117 defer c.mu.Unlock() 118 119 return c.value 120 } 121 122 func TestLoop(t *testing.T) { 123 Convey(".AddListener", t, func() { 124 Convey("Should add a new listener", func() { 125 counter := NewCounter() 126 127 var tes *TestEventStream 128 129 loop := events.NewLoop(events.NewStreamSourceFactory(TestEvent, func(ctx context.Context) (rpcc.Stream, error) { 130 tes = NewTestEventStream() 131 return tes, nil 132 }, func(stream rpcc.Stream) (interface{}, error) { 133 return stream.(*TestEventStream).Recv() 134 })) 135 136 ctx, cancel := context.WithCancel(context.Background()) 137 138 err := loop.Run(ctx) 139 defer cancel() 140 141 So(err, ShouldBeNil) 142 143 tes.EmitDefault() 144 145 wait() 146 147 So(counter.Value(), ShouldEqual, 0) 148 149 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 150 counter.Increase() 151 })) 152 153 wait() 154 155 tes.EmitDefault() 156 157 wait() 158 159 So(counter.Value(), ShouldEqual, 1) 160 }) 161 }) 162 163 Convey(".RemoveListener", t, func() { 164 Convey("Should remove a listener", func() { 165 Convey("Should add a new listener", func() { 166 counter := NewCounter() 167 168 var test *TestEventStream 169 170 loop := events.NewLoop(events.NewStreamSourceFactory(TestEvent, func(ctx context.Context) (rpcc.Stream, error) { 171 test = NewTestEventStream() 172 return test, nil 173 }, func(stream rpcc.Stream) (interface{}, error) { 174 return stream.(*TestEventStream).Recv() 175 })) 176 177 id := loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 178 counter.Increase() 179 })) 180 181 ctx, cancel := context.WithCancel(context.Background()) 182 183 err := loop.Run(ctx) 184 defer cancel() 185 186 So(err, ShouldBeNil) 187 188 test.EmitDefault() 189 190 wait() 191 192 So(counter.Value(), ShouldEqual, 1) 193 194 wait() 195 196 loop.RemoveListener(TestEvent, id) 197 198 wait() 199 200 test.EmitDefault() 201 202 wait() 203 204 So(counter.Value(), ShouldEqual, 1) 205 }) 206 }) 207 }) 208 209 Convey("Should not call listener once it was removed", t, func() { 210 var tes *TestEventStream 211 212 loop := events.NewLoop(events.NewStreamSourceFactory(TestEvent, func(ctx context.Context) (rpcc.Stream, error) { 213 tes = NewTestEventStream() 214 return tes, nil 215 }, func(stream rpcc.Stream) (interface{}, error) { 216 return stream.(*TestEventStream).Recv() 217 })) 218 219 onEvent := make(chan struct{}) 220 221 counter := NewCounter() 222 223 id := loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 224 counter.Increase() 225 226 onEvent <- struct{}{} 227 })) 228 229 go func() { 230 <-onEvent 231 232 loop.RemoveListener(TestEvent, id) 233 }() 234 235 ctx, cancel := context.WithCancel(context.Background()) 236 237 err := loop.Run(ctx) 238 So(err, ShouldBeNil) 239 defer cancel() 240 241 time.Sleep(time.Duration(100) * time.Millisecond) 242 243 tes.EmitDefault() 244 245 time.Sleep(time.Duration(10) * time.Millisecond) 246 247 So(counter.Value(), ShouldEqual, 1) 248 }) 249 250 Convey("Should stop on Context.Done", t, func() { 251 eventsToFire := 5 252 counter := NewCounter() 253 254 var tes *TestEventStream 255 256 loop := events.NewLoop(events.NewStreamSourceFactory(TestEvent, func(ctx context.Context) (rpcc.Stream, error) { 257 tes = NewTestEventStream() 258 return tes, nil 259 }, func(stream rpcc.Stream) (interface{}, error) { 260 return stream.(*TestEventStream).Recv() 261 })) 262 263 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 264 counter.Increase() 265 })) 266 267 ctx, cancel := context.WithCancel(context.Background()) 268 err := loop.Run(ctx) 269 So(err, ShouldBeNil) 270 271 for i := 0; i <= eventsToFire; i++ { 272 time.Sleep(time.Duration(100) * time.Millisecond) 273 274 tes.EmitDefault() 275 } 276 277 // Stop the loop 278 cancel() 279 280 time.Sleep(time.Duration(100) * time.Millisecond) 281 282 So(tes.IsClosed(), ShouldBeTrue) 283 }) 284 } 285 286 func BenchmarkLoop_AddListenerSync(b *testing.B) { 287 loop := events.NewLoop() 288 289 for n := 0; n < b.N; n++ { 290 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) {})) 291 } 292 } 293 294 func BenchmarkLoop_AddListenerAsync(b *testing.B) { 295 loop := events.NewLoop() 296 ctx, cancel := context.WithCancel(context.Background()) 297 298 loop.Run(ctx) 299 defer cancel() 300 301 for n := 0; n < b.N; n++ { 302 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) {})) 303 } 304 } 305 306 func BenchmarkLoop_AddListenerAsync2(b *testing.B) { 307 loop := events.NewLoop() 308 ctx, cancel := context.WithCancel(context.Background()) 309 310 loop.Run(ctx) 311 defer cancel() 312 313 b.RunParallel(func(pb *testing.PB) { 314 for pb.Next() { 315 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) {})) 316 } 317 }) 318 } 319 320 func BenchmarkLoop_Start(b *testing.B) { 321 var tes *TestEventStream 322 323 loop := events.NewLoop(events.NewStreamSourceFactory(TestEvent, func(ctx context.Context) (rpcc.Stream, error) { 324 tes = NewTestEventStream() 325 return tes, nil 326 }, func(stream rpcc.Stream) (interface{}, error) { 327 return stream.(*TestEventStream).Recv() 328 })) 329 330 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 331 332 })) 333 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 334 335 })) 336 337 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 338 339 })) 340 341 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 342 343 })) 344 345 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 346 347 })) 348 349 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 350 351 })) 352 353 ctx, cancel := context.WithCancel(context.Background()) 354 355 if err := loop.Run(ctx); err != nil { 356 panic(err) 357 } 358 359 defer cancel() 360 361 for n := 0; n < b.N; n++ { 362 tes.EmitP("", true) 363 } 364 } 365 366 func BenchmarkLoop_StartAsync(b *testing.B) { 367 var tes *TestEventStream 368 369 loop := events.NewLoop(events.NewStreamSourceFactory(TestEvent, func(ctx context.Context) (rpcc.Stream, error) { 370 tes = NewBufferedTestEventStream(b.N) 371 return tes, nil 372 }, func(stream rpcc.Stream) (interface{}, error) { 373 return stream.(*TestEventStream).Recv() 374 })) 375 376 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 377 378 })) 379 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 380 381 })) 382 383 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 384 385 })) 386 387 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 388 389 })) 390 391 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 392 393 })) 394 395 loop.AddListener(TestEvent, events.Always(func(ctx context.Context, message interface{}) { 396 397 })) 398 399 ctx, cancel := context.WithCancel(context.Background()) 400 401 if err := loop.Run(ctx); err != nil { 402 panic(err) 403 } 404 405 defer cancel() 406 407 b.RunParallel(func(pb *testing.PB) { 408 for pb.Next() { 409 tes.EmitP("", true) 410 } 411 }) 412 }