latch_test.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package asyncbuffer
  2. import (
  3. "sync"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. )
  9. func TestNewLatch(t *testing.T) {
  10. latch := NewLatch()
  11. require.NotNil(t, latch)
  12. require.NotNil(t, latch.done)
  13. // Channel should be open (not closed) initially
  14. select {
  15. case <-latch.done:
  16. t.Fatal("Latch should not be released initially")
  17. default:
  18. // Expected - channel is not ready
  19. }
  20. }
  21. func TestLatchRelease(t *testing.T) {
  22. latch := NewLatch()
  23. // Release the latch
  24. latch.Release()
  25. // Channel should now be closed/ready
  26. select {
  27. case <-latch.done:
  28. // Expected - channel is ready after release
  29. default:
  30. t.Fatal("Latch should be released after Release() call")
  31. }
  32. }
  33. func TestLatchWait(t *testing.T) {
  34. latch := NewLatch()
  35. // Start a goroutine that will wait
  36. waitCompleted := make(chan bool, 1)
  37. go func() {
  38. latch.Wait()
  39. waitCompleted <- true
  40. }()
  41. // Give the goroutine a moment to start waiting
  42. time.Sleep(10 * time.Millisecond)
  43. // Wait should not complete yet
  44. select {
  45. case <-waitCompleted:
  46. t.Fatal("Wait should not complete before Release")
  47. default:
  48. // Expected
  49. }
  50. // Release the latch
  51. latch.Release()
  52. // Wait should complete now
  53. select {
  54. case <-waitCompleted:
  55. // Expected
  56. case <-time.After(100 * time.Millisecond):
  57. t.Fatal("Wait should complete after Release")
  58. }
  59. }
  60. func TestLatchMultipleWaiters(t *testing.T) {
  61. latch := NewLatch()
  62. const numWaiters = 10
  63. var wg sync.WaitGroup
  64. waitersCompleted := make(chan int, numWaiters)
  65. // Start multiple waiters
  66. for i := 0; i < numWaiters; i++ {
  67. wg.Add(1)
  68. go func(id int) {
  69. defer wg.Done()
  70. latch.Wait()
  71. waitersCompleted <- id
  72. }(i)
  73. }
  74. // Give goroutines time to start waiting
  75. time.Sleep(10 * time.Millisecond)
  76. // No waiters should complete yet
  77. assert.Empty(t, waitersCompleted)
  78. // Release the latch
  79. latch.Release()
  80. // All waiters should complete
  81. wg.Wait()
  82. close(waitersCompleted)
  83. // Verify all waiters completed
  84. completed := make([]int, 0, numWaiters)
  85. for id := range waitersCompleted {
  86. completed = append(completed, id)
  87. }
  88. assert.Len(t, completed, numWaiters)
  89. }
  90. func TestLatchMultipleReleases(t *testing.T) {
  91. latch := NewLatch()
  92. // Release multiple times should be safe
  93. latch.Release()
  94. latch.Release()
  95. latch.Release()
  96. // Should still be able to wait
  97. select {
  98. case <-latch.done:
  99. // Expected - channel should be ready
  100. default:
  101. t.Fatal("Latch should be released")
  102. }
  103. }