v3_double_barrier_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright 2016 The etcd Authors
  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. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package integration
  15. import (
  16. "testing"
  17. "time"
  18. "go.etcd.io/etcd/clientv3/concurrency"
  19. "go.etcd.io/etcd/contrib/recipes"
  20. )
  21. func TestDoubleBarrier(t *testing.T) {
  22. clus := NewClusterV3(t, &ClusterConfig{Size: 3})
  23. defer clus.Terminate(t)
  24. waiters := 10
  25. session, err := concurrency.NewSession(clus.RandClient())
  26. if err != nil {
  27. t.Error(err)
  28. }
  29. defer session.Orphan()
  30. b := recipe.NewDoubleBarrier(session, "test-barrier", waiters)
  31. donec := make(chan struct{})
  32. for i := 0; i < waiters-1; i++ {
  33. go func() {
  34. session, err := concurrency.NewSession(clus.RandClient())
  35. if err != nil {
  36. t.Error(err)
  37. }
  38. defer session.Orphan()
  39. bb := recipe.NewDoubleBarrier(session, "test-barrier", waiters)
  40. if err := bb.Enter(); err != nil {
  41. t.Errorf("could not enter on barrier (%v)", err)
  42. }
  43. donec <- struct{}{}
  44. if err := bb.Leave(); err != nil {
  45. t.Errorf("could not leave on barrier (%v)", err)
  46. }
  47. donec <- struct{}{}
  48. }()
  49. }
  50. time.Sleep(10 * time.Millisecond)
  51. select {
  52. case <-donec:
  53. t.Fatalf("barrier did not enter-wait")
  54. default:
  55. }
  56. if err := b.Enter(); err != nil {
  57. t.Fatalf("could not enter last barrier (%v)", err)
  58. }
  59. timerC := time.After(time.Duration(waiters*100) * time.Millisecond)
  60. for i := 0; i < waiters-1; i++ {
  61. select {
  62. case <-timerC:
  63. t.Fatalf("barrier enter timed out")
  64. case <-donec:
  65. }
  66. }
  67. time.Sleep(10 * time.Millisecond)
  68. select {
  69. case <-donec:
  70. t.Fatalf("barrier did not leave-wait")
  71. default:
  72. }
  73. b.Leave()
  74. timerC = time.After(time.Duration(waiters*100) * time.Millisecond)
  75. for i := 0; i < waiters-1; i++ {
  76. select {
  77. case <-timerC:
  78. t.Fatalf("barrier leave timed out")
  79. case <-donec:
  80. }
  81. }
  82. }
  83. func TestDoubleBarrierFailover(t *testing.T) {
  84. clus := NewClusterV3(t, &ClusterConfig{Size: 3})
  85. defer clus.Terminate(t)
  86. waiters := 10
  87. donec := make(chan struct{})
  88. s0, err := concurrency.NewSession(clus.clients[0])
  89. if err != nil {
  90. t.Error(err)
  91. }
  92. defer s0.Orphan()
  93. s1, err := concurrency.NewSession(clus.clients[0])
  94. if err != nil {
  95. t.Error(err)
  96. }
  97. defer s1.Orphan()
  98. // sacrificial barrier holder; lease will be revoked
  99. go func() {
  100. b := recipe.NewDoubleBarrier(s0, "test-barrier", waiters)
  101. if berr := b.Enter(); berr != nil {
  102. t.Errorf("could not enter on barrier (%v)", berr)
  103. }
  104. donec <- struct{}{}
  105. }()
  106. for i := 0; i < waiters-1; i++ {
  107. go func() {
  108. b := recipe.NewDoubleBarrier(s1, "test-barrier", waiters)
  109. if berr := b.Enter(); berr != nil {
  110. t.Errorf("could not enter on barrier (%v)", berr)
  111. }
  112. donec <- struct{}{}
  113. b.Leave()
  114. donec <- struct{}{}
  115. }()
  116. }
  117. // wait for barrier enter to unblock
  118. for i := 0; i < waiters; i++ {
  119. select {
  120. case <-donec:
  121. case <-time.After(10 * time.Second):
  122. t.Fatalf("timed out waiting for enter, %d", i)
  123. }
  124. }
  125. if err = s0.Close(); err != nil {
  126. t.Fatal(err)
  127. }
  128. // join on rest of waiters
  129. for i := 0; i < waiters-1; i++ {
  130. select {
  131. case <-donec:
  132. case <-time.After(10 * time.Second):
  133. t.Fatalf("timed out waiting for leave, %d", i)
  134. }
  135. }
  136. }