github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/chann/chann_test.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 // 14 // ============================================================ 15 // Forked from https://github.com/golang-design/chann. 16 // Copyright 2021 The golang.design Initiative Authors. 17 // All rights reserved. Use of this source code is governed 18 // by a MIT license that can be found in the LICENSE file. 19 // 20 // Written by Changkun Ou <changkun.de> 21 22 package chann 23 24 import ( 25 "runtime" 26 "sync" 27 "sync/atomic" 28 "testing" 29 "time" 30 31 "github.com/stretchr/testify/require" 32 ) 33 34 func TestChan(t *testing.T) { 35 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 36 N := 200 37 if testing.Short() { 38 N = 20 39 } 40 for chanCap := 0; chanCap < N; chanCap++ { 41 { 42 // Ensure that receive from empty chan blocks. 43 c := New[int](Cap(chanCap)) 44 recv1 := false 45 go func() { 46 <-c.Out() 47 recv1 = true 48 }() 49 recv2 := false 50 go func() { 51 <-c.Out() 52 recv2 = true 53 }() 54 time.Sleep(time.Millisecond) 55 require.Falsef(t, recv1, "chan[%d]: receive from empty chan", chanCap) 56 require.Falsef(t, recv2, "chan[%d]: receive from empty chan", chanCap) 57 // Ensure that non-blocking receive does not block. 58 select { 59 case <-c.Out(): 60 t.Fatalf("chan[%d]: receive from empty chan", chanCap) 61 default: 62 } 63 select { 64 case <-c.Out(): 65 t.Fatalf("chan[%d]: receive from empty chan", chanCap) 66 default: 67 } 68 c.In() <- 0 69 c.In() <- 0 70 } 71 72 { 73 // Ensure that send to full chan blocks. 74 c := New[int](Cap(chanCap)) 75 for i := 0; i < chanCap; i++ { 76 c.In() <- i 77 } 78 sent := uint32(0) 79 go func() { 80 c.In() <- 0 81 atomic.StoreUint32(&sent, 1) 82 }() 83 time.Sleep(time.Millisecond) 84 require.Equalf(t, 85 uint32(0), 86 atomic.LoadUint32(&sent), 87 "chan[%d]: send to full chan", chanCap, 88 ) 89 // Ensure that non-blocking send does not block. 90 select { 91 case c.In() <- 0: 92 t.Fatalf("chan[%d]: send to full chan", chanCap) 93 default: 94 } 95 <-c.Out() 96 } 97 98 { 99 // Ensure that we receive 0 from closed chan. 100 c := New[int](Cap(chanCap)) 101 for i := 0; i < chanCap; i++ { 102 c.In() <- i 103 } 104 c.Close() 105 for i := 0; i < chanCap; i++ { 106 v := <-c.Out() 107 require.Equalf(t, i, v, "chan[%d]", chanCap) 108 } 109 v := <-c.Out() 110 require.Equalf(t, 0, v, "chan[%d]", chanCap) 111 v, ok := <-c.Out() 112 require.Equalf(t, 0, v, "chan[%d]", chanCap) 113 require.Falsef(t, ok, "chan[%d]", chanCap) 114 } 115 116 { 117 // Ensure that close unblocks receive. 118 c := New[int](Cap(chanCap)) 119 done := make(chan bool) 120 go func() { 121 v, ok := <-c.Out() 122 done <- v == 0 && ok == false 123 }() 124 time.Sleep(time.Millisecond) 125 c.Close() 126 require.Truef(t, <-done, "chan[%d]: received non zero from closed chan", chanCap) 127 } 128 129 { 130 // Send 100 integers, 131 // ensure that we receive them non-corrupted in FIFO order. 132 c := New[int](Cap(chanCap)) 133 go func() { 134 for i := 0; i < 100; i++ { 135 c.In() <- i 136 } 137 }() 138 for i := 0; i < 100; i++ { 139 v := <-c.Out() 140 require.Equalf(t, i, v, "chan[%d]", chanCap) 141 } 142 143 // Same, but using recv2. 144 go func() { 145 for i := 0; i < 100; i++ { 146 c.In() <- i 147 } 148 }() 149 for i := 0; i < 100; i++ { 150 v, ok := <-c.Out() 151 require.Truef(t, ok, "chan[%d]: receive failed, expected %v", chanCap, i) 152 require.Equalf(t, i, v, "chan[%d]", chanCap) 153 } 154 155 // Send 1000 integers in 4 goroutines, 156 // ensure that we receive what we send. 157 const P = 4 158 const L = 1000 159 for p := 0; p < P; p++ { 160 go func() { 161 for i := 0; i < L; i++ { 162 c.In() <- i 163 } 164 }() 165 } 166 done := New[map[int]int](Cap(0)) 167 for p := 0; p < P; p++ { 168 go func() { 169 recv := make(map[int]int) 170 for i := 0; i < L; i++ { 171 v := <-c.Out() 172 recv[v] = recv[v] + 1 173 } 174 done.In() <- recv 175 }() 176 } 177 recv := make(map[int]int) 178 for p := 0; p < P; p++ { 179 for k, v := range <-done.Out() { 180 recv[k] = recv[k] + v 181 } 182 } 183 require.Lenf(t, recv, L, "chan[%d]", chanCap) 184 for _, v := range recv { 185 require.Equalf(t, P, v, "chan[%d]", chanCap) 186 } 187 } 188 189 { 190 // Test len/cap. 191 c := New[int](Cap(chanCap)) 192 require.Equalf(t, 0, c.Len(), "chan[%d]", chanCap) 193 require.Equalf(t, chanCap, c.Cap(), "chan[%d]", chanCap) 194 for i := 0; i < chanCap; i++ { 195 c.In() <- i 196 } 197 require.Equalf(t, chanCap, c.Len(), "chan[%d]", chanCap) 198 require.Equalf(t, chanCap, c.Cap(), "chan[%d]", chanCap) 199 } 200 } 201 } 202 203 func TestNonblockRecvRace(t *testing.T) { 204 n := 10000 205 if testing.Short() { 206 n = 100 207 } 208 for i := 0; i < n; i++ { 209 c := New[int](Cap(1)) 210 c.In() <- 1 211 t.Log(i) 212 go func() { 213 select { 214 case <-c.Out(): 215 default: 216 t.Error("chan is not ready") 217 } 218 }() 219 c.Close() 220 <-c.Out() 221 if t.Failed() { 222 return 223 } 224 } 225 } 226 227 const internalCacheSize = 16 + 1<<10 228 229 // This test checks that select acts on the state of the channels at one 230 // moment in the execution, not over a smeared time window. 231 // In the test, one goroutine does: 232 // 233 // create c1, c2 234 // make c1 ready for receiving 235 // create second goroutine 236 // make c2 ready for receiving 237 // 238 // The second goroutine does a non-blocking select receiving from c1 and c2. 239 // From the time the second goroutine is created, at least one of c1 and c2 240 // is always ready for receiving, so the select in the second goroutine must 241 // always receive from one or the other. It must never execute the default case. 242 func TestNonblockSelectRace(t *testing.T) { 243 n := 1000 244 done := New[bool](Cap(1)) 245 for i := 0; i < n; i++ { 246 c1 := New[int]() 247 c2 := New[int]() 248 // The input channel of an unbounded buffer have an internal 249 // cache queue. When the input channel and the internal cache 250 // queue both gets full, we are certain that once the next send 251 // is complete, the out will be available for sure hence the 252 // waiting time of a receive is bounded. 253 for i := 0; i < internalCacheSize; i++ { 254 c1.In() <- 1 255 } 256 c1.In() <- 1 257 go func() { 258 runtime.Gosched() 259 select { 260 case <-c1.Out(): 261 case <-c2.Out(): 262 default: 263 done.In() <- false 264 return 265 } 266 done.In() <- true 267 }() 268 // Same for c2 269 for i := 0; i < internalCacheSize; i++ { 270 c2.In() <- 1 271 } 272 c2.In() <- 1 273 select { 274 case <-c1.Out(): 275 default: 276 } 277 require.Truef(t, <-done.Out(), "no chan is ready") 278 c1.Close() 279 // Drop all events. 280 for range c1.Out() { 281 } 282 c2.Close() 283 for range c2.Out() { 284 } 285 } 286 } 287 288 // Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1. 289 func TestNonblockSelectRace2(t *testing.T) { 290 n := 1000 291 done := make(chan bool, 1) 292 for i := 0; i < n; i++ { 293 c1 := New[int]() 294 c2 := New[int]() 295 // See TestNonblockSelectRace. 296 for i := 0; i < internalCacheSize; i++ { 297 c1.In() <- 1 298 } 299 c1.In() <- 1 300 go func() { 301 select { 302 case <-c1.Out(): 303 case <-c2.Out(): 304 default: 305 done <- false 306 return 307 } 308 done <- true 309 }() 310 c2.Close() 311 select { 312 case <-c1.Out(): 313 default: 314 } 315 require.Truef(t, <-done, "no chan is ready") 316 c1.Close() 317 // Drop all events. 318 for range c1.Out() { 319 } 320 } 321 } 322 323 func TestUnboundedChann(t *testing.T) { 324 N := 200 325 if testing.Short() { 326 N = 20 327 } 328 329 wg := sync.WaitGroup{} 330 for i := 0; i < N; i++ { 331 t.Run("interface{}", func(t *testing.T) { 332 t.Run("send", func(t *testing.T) { 333 // Ensure send to an unbounded channel does not block. 334 c := New[interface{}]() 335 blocked := false 336 wg.Add(1) 337 go func() { 338 defer wg.Done() 339 select { 340 case c.In() <- true: 341 default: 342 blocked = true 343 } 344 }() 345 wg.Wait() 346 require.Falsef(t, blocked, "send op to an unbounded channel blocked") 347 c.Close() 348 }) 349 350 t.Run("recv", func(t *testing.T) { 351 // Ensure that receive op from unbounded chan can happen on 352 // the same goroutine of send op. 353 c := New[interface{}]() 354 wg.Add(1) 355 go func() { 356 defer wg.Done() 357 c.In() <- true 358 <-c.Out() 359 }() 360 wg.Wait() 361 c.Close() 362 }) 363 t.Run("order", func(t *testing.T) { 364 // Ensure that the unbounded channel processes everything FIFO. 365 c := New[interface{}]() 366 for i := 0; i < 1<<11; i++ { 367 c.In() <- i 368 } 369 for i := 0; i < 1<<11; i++ { 370 val := <-c.Out() 371 require.Equalf( 372 t, 373 i, 374 val, 375 "unbounded channel passes messages in a non-FIFO order", 376 ) 377 } 378 c.Close() 379 }) 380 }) 381 t.Run("struct{}", func(t *testing.T) { 382 t.Run("send", func(t *testing.T) { 383 // Ensure send to an unbounded channel does not block. 384 c := New[struct{}]() 385 blocked := false 386 wg.Add(1) 387 go func() { 388 defer wg.Done() 389 select { 390 case c.In() <- struct{}{}: 391 default: 392 blocked = true 393 } 394 }() 395 <-c.Out() 396 wg.Wait() 397 require.Falsef(t, blocked, "send op to an unbounded channel blocked") 398 c.Close() 399 }) 400 401 t.Run("recv", func(t *testing.T) { 402 // Ensure that receive op from unbounded chan can happen on 403 // the same goroutine of send op. 404 c := New[struct{}]() 405 wg.Add(1) 406 go func() { 407 defer wg.Done() 408 c.In() <- struct{}{} 409 <-c.Out() 410 }() 411 wg.Wait() 412 c.Close() 413 }) 414 t.Run("order", func(t *testing.T) { 415 // Ensure that the unbounded channel processes everything FIFO. 416 c := New[struct{}]() 417 for i := 0; i < 1<<11; i++ { 418 c.In() <- struct{}{} 419 } 420 n := 0 421 for i := 0; i < 1<<11; i++ { 422 if _, ok := <-c.Out(); ok { 423 n++ 424 } 425 } 426 require.Equalf(t, 1<<11, n, "unbounded channel missed a message") 427 c.Close() 428 }) 429 }) 430 } 431 } 432 433 func TestUnboundedChannClose(t *testing.T) { 434 t.Run("close-status", func(t *testing.T) { 435 ch := New[any]() 436 for i := 0; i < 100; i++ { 437 ch.In() <- 0 438 } 439 ch.Close() 440 go func() { 441 for range ch.Out() { 442 } 443 }() 444 445 // Theoretically, this is not a dead loop. If the channel 446 // is closed, then this loop must terminate at somepoint. 447 // If not, we will meet timeout in the test. 448 for !ch.isClosed() { 449 t.Log("unbounded channel is still not entirely closed") 450 } 451 }) 452 t.Run("struct{}", func(t *testing.T) { 453 grs := runtime.NumGoroutine() 454 N := 10 455 n := 0 456 done := make(chan struct{}) 457 ch := New[struct{}]() 458 for i := 0; i < N; i++ { 459 ch.In() <- struct{}{} 460 } 461 go func() { 462 for range ch.Out() { 463 n++ 464 } 465 done <- struct{}{} 466 }() 467 ch.Close() 468 <-done 469 runtime.GC() 470 require.LessOrEqualf(t, runtime.NumGoroutine(), grs+2, "leaking goroutines: %v", n) 471 require.Equalf(t, N, n, "After close, not all elements are received") 472 }) 473 474 t.Run("interface{}", func(t *testing.T) { 475 grs := runtime.NumGoroutine() 476 N := 10 477 n := 0 478 done := make(chan struct{}) 479 ch := New[interface{}]() 480 for i := 0; i < N; i++ { 481 ch.In() <- true 482 } 483 go func() { 484 for range ch.Out() { 485 n++ 486 } 487 done <- struct{}{} 488 }() 489 ch.Close() 490 <-done 491 runtime.GC() 492 require.LessOrEqualf(t, runtime.NumGoroutine(), grs+2, "leaking goroutines: %v", n) 493 require.Equalf(t, N, n, "After close, not all elements are received") 494 }) 495 } 496 497 func BenchmarkUnboundedChann(b *testing.B) { 498 b.Run("interface{}", func(b *testing.B) { 499 b.Run("sync", func(b *testing.B) { 500 c := New[interface{}]() 501 defer c.Close() 502 b.ResetTimer() 503 b.ReportAllocs() 504 for i := 0; i < b.N; i++ { 505 c.In() <- struct{}{} 506 <-c.Out() 507 } 508 }) 509 b.Run("chann", func(b *testing.B) { 510 c := New[interface{}]() 511 defer c.Close() 512 b.ResetTimer() 513 b.ReportAllocs() 514 for i := 0; i < b.N; i++ { 515 go func() { c.In() <- struct{}{} }() 516 <-c.Out() 517 } 518 }) 519 }) 520 b.Run("struct{}", func(b *testing.B) { 521 b.Run("sync", func(b *testing.B) { 522 c := New[struct{}]() 523 defer c.Close() 524 b.ResetTimer() 525 b.ReportAllocs() 526 for i := 0; i < b.N; i++ { 527 c.In() <- struct{}{} 528 <-c.Out() 529 } 530 }) 531 b.Run("chann", func(b *testing.B) { 532 c := New[struct{}]() 533 defer c.Close() 534 b.ResetTimer() 535 b.ReportAllocs() 536 for i := 0; i < b.N; i++ { 537 go func() { c.In() <- struct{}{} }() 538 <-c.Out() 539 } 540 }) 541 }) 542 }