github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/util/etcd/election_test.go (about) 1 // Copyright 2018 Google Inc. All Rights Reserved. 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 etcd 16 17 import ( 18 "context" 19 "sync" 20 "testing" 21 "time" 22 23 "github.com/coreos/etcd/clientv3" 24 "github.com/google/trillian/testonly/integration/etcd" 25 "github.com/google/trillian/util/election" 26 ) 27 28 func TestMasterElectionThroughCommonClient(t *testing.T) { 29 _, client, cleanup, err := etcd.StartEtcd() 30 if err != nil { 31 t.Fatalf("StartEtcd(): %v", err) 32 } 33 defer cleanup() 34 35 ctx := context.Background() 36 fact := NewElectionFactory("serv", client, "trees/") 37 38 el1, err := fact.NewElection(ctx, 10) 39 if err != nil { 40 t.Fatalf("NewElection(10): %v", err) 41 } 42 el2, err := fact.NewElection(ctx, 20) 43 if err != nil { 44 t.Fatalf("NewElection(20): %v", err) 45 } 46 47 if err := el1.WaitForMastership(ctx); err != nil { 48 t.Fatalf("WaitForMastership(10): %v", err) 49 } 50 if err := el2.WaitForMastership(ctx); err != nil { 51 t.Fatalf("WaitForMastership(20): %v", err) 52 } 53 54 if err := el1.Close(ctx); err != nil { 55 t.Fatalf("Close(10): %v", err) 56 } 57 if err := el2.Close(ctx); err != nil { 58 t.Fatalf("Close(20): %v", err) 59 } 60 } 61 62 func everyoneAgreesOnMaster(ctx context.Context, t *testing.T, want string, elections []election.MasterElection) { 63 t.Helper() 64 for _, e := range elections { 65 for { 66 got, err := e.GetCurrentMaster(ctx) 67 if err == election.ErrNoMaster { 68 t.Error("No leader...") 69 time.Sleep(time.Second) 70 continue 71 } else if err != nil { 72 t.Fatalf("Failed to GetCurrentMaster: %v", err) 73 } 74 if got != want { 75 t.Errorf("Current master is %v, want %v", got, want) 76 } 77 break 78 } 79 } 80 } 81 82 func mustCreateClientFor(t *testing.T, e string) *clientv3.Client { 83 t.Helper() 84 c, err := clientv3.New(clientv3.Config{ 85 Endpoints: []string{e}, 86 }) 87 if err != nil { 88 t.Fatalf("Error creating etcd client: %v", err) 89 } 90 return c 91 } 92 93 func TestGetCurrentMaster(t *testing.T) { 94 e, client, cleanup, err := etcd.StartEtcd() 95 if err != nil { 96 t.Fatalf("StartEtcd(): %v", err) 97 } 98 defer cleanup() 99 // add another active participant 100 client2 := mustCreateClientFor(t, e.Config().LCUrls[0].String()) 101 defer client2.Close() 102 103 // add a couple of passive observers 104 ob1 := mustCreateClientFor(t, e.Config().LCUrls[0].String()) 105 defer ob1.Close() 106 ob2 := mustCreateClientFor(t, e.Config().LCUrls[0].String()) 107 defer ob2.Close() 108 109 ctx := context.Background() 110 pfx := "trees/" 111 facts := []*ElectionFactory{ 112 NewElectionFactory("serv1", client, pfx), 113 NewElectionFactory("serv2", client2, pfx), 114 NewElectionFactory("ob1", ob1, pfx), 115 NewElectionFactory("ob2", ob2, pfx), 116 } 117 118 elections := make([]election.MasterElection, 0) 119 for _, f := range facts { 120 e, err := f.NewElection(ctx, 10) 121 if err != nil { 122 t.Fatalf("NewElection(10): %v", err) 123 } 124 elections = append(elections, e) 125 } 126 127 wg := &sync.WaitGroup{} 128 for _, e := range elections[0:2] { 129 wg.Add(1) 130 go func(e election.MasterElection) { 131 if err := e.WaitForMastership(ctx); err != nil { 132 t.Errorf("WaitForMastership(10): %v", err) 133 } 134 id := e.(*MasterElection).instanceID 135 136 everyoneAgreesOnMaster(ctx, t, id, elections) 137 if err := e.Close(ctx); err != nil { 138 t.Errorf("Close(10): %v", err) 139 } 140 wg.Done() 141 }(e) 142 } 143 wg.Wait() 144 } 145 146 func TestGetCurrentMasterReturnsNoLeader(t *testing.T) { 147 ctx := context.Background() 148 _, client, cleanup, err := etcd.StartEtcd() 149 if err != nil { 150 t.Fatalf("StartEtcd(): %v", err) 151 } 152 defer cleanup() 153 fact := NewElectionFactory("serv1", client, "trees/") 154 el, err := fact.NewElection(ctx, 10) 155 if err != nil { 156 t.Fatalf("NewElection(10): %v", err) 157 } 158 if err := el.WaitForMastership(ctx); err != nil { 159 t.Errorf("WaitForMastership(10): %v", err) 160 } 161 if err := el.Close(ctx); err != nil { 162 t.Errorf("Close(10): %v", err) 163 } 164 _, err = el.GetCurrentMaster(ctx) 165 if want := election.ErrNoMaster; err != want { 166 t.Errorf("GetCurrentMaster()=%v, want %v", err, want) 167 } 168 }