gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/grpc/picker_wrapper_test.go (about) 1 /* 2 * 3 * Copyright 2017 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package grpc 20 21 import ( 22 "context" 23 "fmt" 24 "sync/atomic" 25 "testing" 26 "time" 27 28 "gitee.com/zhaochuninhefei/gmgo/grpc/balancer" 29 "gitee.com/zhaochuninhefei/gmgo/grpc/codes" 30 "gitee.com/zhaochuninhefei/gmgo/grpc/connectivity" 31 "gitee.com/zhaochuninhefei/gmgo/grpc/internal/transport" 32 "gitee.com/zhaochuninhefei/gmgo/grpc/status" 33 ) 34 35 const goroutineCount = 5 36 37 var ( 38 testT = &testTransport{} 39 testSC = &acBalancerWrapper{ac: &addrConn{ 40 state: connectivity.Ready, 41 transport: testT, 42 }} 43 testSCNotReady = &acBalancerWrapper{ac: &addrConn{ 44 state: connectivity.TransientFailure, 45 }} 46 ) 47 48 type testTransport struct { 49 transport.ClientTransport 50 } 51 52 type testingPicker struct { 53 err error 54 sc balancer.SubConn 55 maxCalled int64 56 } 57 58 //goland:noinspection GoUnusedParameter 59 func (p *testingPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { 60 if atomic.AddInt64(&p.maxCalled, -1) < 0 { 61 return balancer.PickResult{}, fmt.Errorf("pick called to many times (> goroutineCount)") 62 } 63 if p.err != nil { 64 return balancer.PickResult{}, p.err 65 } 66 return balancer.PickResult{SubConn: p.sc}, nil 67 } 68 69 func (s) TestBlockingPickTimeout(t *testing.T) { 70 bp := newPickerWrapper() 71 ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond) 72 defer cancel() 73 if _, _, err := bp.pick(ctx, true, balancer.PickInfo{}); status.Code(err) != codes.DeadlineExceeded { 74 t.Errorf("bp.pick returned error %v, want DeadlineExceeded", err) 75 } 76 } 77 78 func (s) TestBlockingPick(t *testing.T) { 79 bp := newPickerWrapper() 80 // All goroutines should block because picker is nil in bp. 81 var finishedCount uint64 82 for i := goroutineCount; i > 0; i-- { 83 go func() { 84 if tr, _, err := bp.pick(context.Background(), true, balancer.PickInfo{}); err != nil || tr != testT { 85 t.Errorf("bp.pick returned non-nil error: %v", err) 86 } 87 atomic.AddUint64(&finishedCount, 1) 88 }() 89 } 90 time.Sleep(50 * time.Millisecond) 91 if c := atomic.LoadUint64(&finishedCount); c != 0 { 92 t.Errorf("finished goroutines count: %v, want 0", c) 93 } 94 bp.updatePicker(&testingPicker{sc: testSC, maxCalled: goroutineCount}) 95 } 96 97 func (s) TestBlockingPickNoSubAvailable(t *testing.T) { 98 bp := newPickerWrapper() 99 var finishedCount uint64 100 bp.updatePicker(&testingPicker{err: balancer.ErrNoSubConnAvailable, maxCalled: goroutineCount}) 101 // All goroutines should block because picker returns no sc available. 102 for i := goroutineCount; i > 0; i-- { 103 go func() { 104 if tr, _, err := bp.pick(context.Background(), true, balancer.PickInfo{}); err != nil || tr != testT { 105 t.Errorf("bp.pick returned non-nil error: %v", err) 106 } 107 atomic.AddUint64(&finishedCount, 1) 108 }() 109 } 110 time.Sleep(50 * time.Millisecond) 111 if c := atomic.LoadUint64(&finishedCount); c != 0 { 112 t.Errorf("finished goroutines count: %v, want 0", c) 113 } 114 bp.updatePicker(&testingPicker{sc: testSC, maxCalled: goroutineCount}) 115 } 116 117 func (s) TestBlockingPickTransientWaitforready(t *testing.T) { 118 bp := newPickerWrapper() 119 //goland:noinspection GoDeprecation 120 bp.updatePicker(&testingPicker{err: balancer.ErrTransientFailure, maxCalled: goroutineCount}) 121 var finishedCount uint64 122 // All goroutines should block because picker returns transientFailure and 123 // picks are not failfast. 124 for i := goroutineCount; i > 0; i-- { 125 go func() { 126 if tr, _, err := bp.pick(context.Background(), false, balancer.PickInfo{}); err != nil || tr != testT { 127 t.Errorf("bp.pick returned non-nil error: %v", err) 128 } 129 atomic.AddUint64(&finishedCount, 1) 130 }() 131 } 132 time.Sleep(time.Millisecond) 133 if c := atomic.LoadUint64(&finishedCount); c != 0 { 134 t.Errorf("finished goroutines count: %v, want 0", c) 135 } 136 bp.updatePicker(&testingPicker{sc: testSC, maxCalled: goroutineCount}) 137 } 138 139 func (s) TestBlockingPickSCNotReady(t *testing.T) { 140 bp := newPickerWrapper() 141 bp.updatePicker(&testingPicker{sc: testSCNotReady, maxCalled: goroutineCount}) 142 var finishedCount uint64 143 // All goroutines should block because sc is not ready. 144 for i := goroutineCount; i > 0; i-- { 145 go func() { 146 if tr, _, err := bp.pick(context.Background(), true, balancer.PickInfo{}); err != nil || tr != testT { 147 t.Errorf("bp.pick returned non-nil error: %v", err) 148 } 149 atomic.AddUint64(&finishedCount, 1) 150 }() 151 } 152 time.Sleep(time.Millisecond) 153 if c := atomic.LoadUint64(&finishedCount); c != 0 { 154 t.Errorf("finished goroutines count: %v, want 0", c) 155 } 156 bp.updatePicker(&testingPicker{sc: testSC, maxCalled: goroutineCount}) 157 }