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