syncs_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package syncs
  4. import (
  5. "context"
  6. "sync"
  7. "testing"
  8. "github.com/google/go-cmp/cmp"
  9. )
  10. func TestWaitGroupChan(t *testing.T) {
  11. wg := NewWaitGroupChan()
  12. wantNotDone := func() {
  13. t.Helper()
  14. select {
  15. case <-wg.DoneChan():
  16. t.Fatal("done too early")
  17. default:
  18. }
  19. }
  20. wantDone := func() {
  21. t.Helper()
  22. select {
  23. case <-wg.DoneChan():
  24. default:
  25. t.Fatal("expected to be done")
  26. }
  27. }
  28. wg.Add(2)
  29. wantNotDone()
  30. wg.Decr()
  31. wantNotDone()
  32. wg.Decr()
  33. wantDone()
  34. wantDone()
  35. }
  36. func TestClosedChan(t *testing.T) {
  37. ch := ClosedChan()
  38. for i := 0; i < 2; i++ {
  39. select {
  40. case <-ch:
  41. default:
  42. t.Fatal("not closed")
  43. }
  44. }
  45. }
  46. func TestSemaphore(t *testing.T) {
  47. s := NewSemaphore(2)
  48. s.Acquire()
  49. if !s.TryAcquire() {
  50. t.Fatal("want true")
  51. }
  52. if s.TryAcquire() {
  53. t.Fatal("want false")
  54. }
  55. ctx, cancel := context.WithCancel(context.Background())
  56. cancel()
  57. if s.AcquireContext(ctx) {
  58. t.Fatal("want false")
  59. }
  60. s.Release()
  61. if !s.AcquireContext(context.Background()) {
  62. t.Fatal("want true")
  63. }
  64. s.Release()
  65. s.Release()
  66. }
  67. func TestMap(t *testing.T) {
  68. var m Map[string, int]
  69. if v, ok := m.Load("noexist"); v != 0 || ok {
  70. t.Errorf(`Load("noexist") = (%v, %v), want (0, false)`, v, ok)
  71. }
  72. m.LoadFunc("noexist", func(v int, ok bool) {
  73. if v != 0 || ok {
  74. t.Errorf(`LoadFunc("noexist") = (%v, %v), want (0, false)`, v, ok)
  75. }
  76. })
  77. m.Store("one", 1)
  78. if v, ok := m.LoadOrStore("one", -1); v != 1 || !ok {
  79. t.Errorf(`LoadOrStore("one", 1) = (%v, %v), want (1, true)`, v, ok)
  80. }
  81. if v, ok := m.Load("one"); v != 1 || !ok {
  82. t.Errorf(`Load("one") = (%v, %v), want (1, true)`, v, ok)
  83. }
  84. m.LoadFunc("one", func(v int, ok bool) {
  85. if v != 1 || !ok {
  86. t.Errorf(`LoadFunc("one") = (%v, %v), want (1, true)`, v, ok)
  87. }
  88. })
  89. if v, ok := m.LoadOrStore("two", 2); v != 2 || ok {
  90. t.Errorf(`LoadOrStore("two", 2) = (%v, %v), want (2, false)`, v, ok)
  91. }
  92. if v, ok := m.LoadOrInit("three", func() int { return 3 }); v != 3 || ok {
  93. t.Errorf(`LoadOrInit("three", 3) = (%v, %v), want (3, true)`, v, ok)
  94. }
  95. got := map[string]int{}
  96. want := map[string]int{"one": 1, "two": 2, "three": 3}
  97. m.Range(func(k string, v int) bool {
  98. got[k] = v
  99. return true
  100. })
  101. if d := cmp.Diff(got, want); d != "" {
  102. t.Errorf("Range mismatch (-got +want):\n%s", d)
  103. }
  104. if v, ok := m.LoadAndDelete("two"); v != 2 || !ok {
  105. t.Errorf(`LoadAndDelete("two) = (%v, %v), want (2, true)`, v, ok)
  106. }
  107. if v, ok := m.LoadAndDelete("two"); v != 0 || ok {
  108. t.Errorf(`LoadAndDelete("two) = (%v, %v), want (0, false)`, v, ok)
  109. }
  110. m.Delete("three")
  111. m.Delete("one")
  112. m.Delete("noexist")
  113. got = map[string]int{}
  114. want = map[string]int{}
  115. m.Range(func(k string, v int) bool {
  116. got[k] = v
  117. return true
  118. })
  119. if d := cmp.Diff(got, want); d != "" {
  120. t.Errorf("Range mismatch (-got +want):\n%s", d)
  121. }
  122. t.Run("LoadOrStore", func(t *testing.T) {
  123. var m Map[string, string]
  124. var wg sync.WaitGroup
  125. wg.Add(2)
  126. var ok1, ok2 bool
  127. go func() {
  128. defer wg.Done()
  129. _, ok1 = m.LoadOrStore("", "")
  130. }()
  131. go func() {
  132. defer wg.Done()
  133. _, ok2 = m.LoadOrStore("", "")
  134. }()
  135. wg.Wait()
  136. if ok1 == ok2 {
  137. t.Errorf("exactly one LoadOrStore should load")
  138. }
  139. })
  140. t.Run("Clear", func(t *testing.T) {
  141. var m Map[string, string]
  142. _, _ = m.LoadOrStore("a", "1")
  143. _, _ = m.LoadOrStore("b", "2")
  144. _, _ = m.LoadOrStore("c", "3")
  145. _, _ = m.LoadOrStore("d", "4")
  146. _, _ = m.LoadOrStore("e", "5")
  147. if m.Len() != 5 {
  148. t.Errorf("Len after loading want=5 got=%d", m.Len())
  149. }
  150. m.Clear()
  151. if m.Len() != 0 {
  152. t.Errorf("Len after Clear want=0 got=%d", m.Len())
  153. }
  154. })
  155. }