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