sharedcalls_test.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package syncx
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "sync/atomic"
  7. "testing"
  8. "time"
  9. )
  10. func TestExclusiveCallDo(t *testing.T) {
  11. g := NewSharedCalls()
  12. v, err := g.Do("key", func() (interface{}, error) {
  13. return "bar", nil
  14. })
  15. if got, want := fmt.Sprintf("%v (%T)", v, v), "bar (string)"; got != want {
  16. t.Errorf("Do = %v; want %v", got, want)
  17. }
  18. if err != nil {
  19. t.Errorf("Do error = %v", err)
  20. }
  21. }
  22. func TestExclusiveCallDoErr(t *testing.T) {
  23. g := NewSharedCalls()
  24. someErr := errors.New("some error")
  25. v, err := g.Do("key", func() (interface{}, error) {
  26. return nil, someErr
  27. })
  28. if err != someErr {
  29. t.Errorf("Do error = %v; want someErr", err)
  30. }
  31. if v != nil {
  32. t.Errorf("unexpected non-nil value %#v", v)
  33. }
  34. }
  35. func TestExclusiveCallDoDupSuppress(t *testing.T) {
  36. g := NewSharedCalls()
  37. c := make(chan string)
  38. var calls int32
  39. fn := func() (interface{}, error) {
  40. atomic.AddInt32(&calls, 1)
  41. return <-c, nil
  42. }
  43. const n = 10
  44. var wg sync.WaitGroup
  45. for i := 0; i < n; i++ {
  46. wg.Add(1)
  47. go func() {
  48. v, err := g.Do("key", fn)
  49. if err != nil {
  50. t.Errorf("Do error: %v", err)
  51. }
  52. if v.(string) != "bar" {
  53. t.Errorf("got %q; want %q", v, "bar")
  54. }
  55. wg.Done()
  56. }()
  57. }
  58. time.Sleep(100 * time.Millisecond) // let goroutines above block
  59. c <- "bar"
  60. wg.Wait()
  61. if got := atomic.LoadInt32(&calls); got != 1 {
  62. t.Errorf("number of calls = %d; want 1", got)
  63. }
  64. }
  65. func TestExclusiveCallDoExDupSuppress(t *testing.T) {
  66. g := NewSharedCalls()
  67. c := make(chan string)
  68. var calls int32
  69. fn := func() (interface{}, error) {
  70. atomic.AddInt32(&calls, 1)
  71. return <-c, nil
  72. }
  73. const n = 10
  74. var wg sync.WaitGroup
  75. var freshes int32
  76. for i := 0; i < n; i++ {
  77. wg.Add(1)
  78. go func() {
  79. v, fresh, err := g.DoEx("key", fn)
  80. if err != nil {
  81. t.Errorf("Do error: %v", err)
  82. }
  83. if fresh {
  84. atomic.AddInt32(&freshes, 1)
  85. }
  86. if v.(string) != "bar" {
  87. t.Errorf("got %q; want %q", v, "bar")
  88. }
  89. wg.Done()
  90. }()
  91. }
  92. time.Sleep(100 * time.Millisecond) // let goroutines above block
  93. c <- "bar"
  94. wg.Wait()
  95. if got := atomic.LoadInt32(&calls); got != 1 {
  96. t.Errorf("number of calls = %d; want 1", got)
  97. }
  98. if got := atomic.LoadInt32(&freshes); got != 1 {
  99. t.Errorf("freshes = %d; want 1", got)
  100. }
  101. }