TestThreeBackendsAffinity covers that there are 3 SubConns, RPCs with the same hash always pick the same SubConn. When the one picked is down, another one will be picked.
(t *testing.T)
| 186 | // same hash always pick the same SubConn. When the one picked is down, another |
| 187 | // one will be picked. |
| 188 | func (s) TestThreeSubConnsAffinity(t *testing.T) { |
| 189 | endpoints := []resolver.Endpoint{ |
| 190 | {Addresses: []resolver.Address{{Addr: testBackendAddrStrs[0]}}}, |
| 191 | {Addresses: []resolver.Address{{Addr: testBackendAddrStrs[1]}}}, |
| 192 | {Addresses: []resolver.Address{{Addr: testBackendAddrStrs[2]}}}, |
| 193 | } |
| 194 | remainingAddrs := map[string]bool{ |
| 195 | testBackendAddrStrs[0]: true, |
| 196 | testBackendAddrStrs[1]: true, |
| 197 | testBackendAddrStrs[2]: true, |
| 198 | } |
| 199 | cc, _, p0 := setupTest(t, endpoints) |
| 200 | // This test doesn't update addresses, so this ring will be used by all the |
| 201 | // pickers. |
| 202 | ring := p0.(*picker).ring |
| 203 | |
| 204 | firstHash := ring.items[0].hash |
| 205 | // firstHash+1 will pick the second endpoint from the ring. |
| 206 | testHash := firstHash + 1 |
| 207 | // The first pick should be queued, and should trigger Connect() on the only |
| 208 | // SubConn. |
| 209 | ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) |
| 210 | defer cancel() |
| 211 | if _, err := p0.Pick(balancer.PickInfo{Ctx: iringhash.SetXDSRequestHash(ctx, testHash)}); err != balancer.ErrNoSubConnAvailable { |
| 212 | t.Fatalf("first pick returned err %v, want %v", err, balancer.ErrNoSubConnAvailable) |
| 213 | } |
| 214 | |
| 215 | // The picked endpoint should be the second in the ring. |
| 216 | var subConns [3]*testutils.TestSubConn |
| 217 | select { |
| 218 | case <-ctx.Done(): |
| 219 | t.Fatalf("Timed out waiting for SubConn creation.") |
| 220 | case subConns[1] = <-cc.NewSubConnCh: |
| 221 | } |
| 222 | if got, want := subConns[1].Addresses[0].Addr, ring.items[1].hashKey; got != want { |
| 223 | t.Fatalf("SubConn.Address = %v, want = %v", got, want) |
| 224 | } |
| 225 | select { |
| 226 | case <-subConns[1].ConnectCh: |
| 227 | case <-time.After(defaultTestTimeout): |
| 228 | t.Errorf("timeout waiting for Connect() from SubConn %v", subConns[1]) |
| 229 | } |
| 230 | delete(remainingAddrs, ring.items[1].hashKey) |
| 231 | |
| 232 | // Turn down the subConn in use. |
| 233 | subConns[1].UpdateState(balancer.SubConnState{ConnectivityState: connectivity.Connecting}) |
| 234 | subConns[1].UpdateState(balancer.SubConnState{ConnectivityState: connectivity.TransientFailure}) |
| 235 | |
| 236 | // This should trigger a connection to a new endpoint. |
| 237 | <-cc.NewPickerCh |
| 238 | var sc *testutils.TestSubConn |
| 239 | select { |
| 240 | case <-ctx.Done(): |
| 241 | t.Fatalf("Timed out waiting for SubConn creation.") |
| 242 | case sc = <-cc.NewSubConnCh: |
| 243 | } |
| 244 | scAddr := sc.Addresses[0].Addr |
| 245 | if _, ok := remainingAddrs[scAddr]; !ok { |
nothing calls this directly
no test coverage detected