19
19
package clusterresolver
20
20
21
21
import (
22
- "context"
23
- "fmt"
24
22
"testing"
25
23
"time"
26
24
27
- "github.com/google/go-cmp/cmp"
28
- "github.com/google/go-cmp/cmp/cmpopts"
29
- "google.golang.org/grpc/balancer"
30
- "google.golang.org/grpc/connectivity"
31
25
"google.golang.org/grpc/internal/grpctest"
32
- iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
33
- "google.golang.org/grpc/internal/testutils"
34
- "google.golang.org/grpc/resolver"
35
- xdsinternal "google.golang.org/grpc/xds/internal"
36
- "google.golang.org/grpc/xds/internal/balancer/clusterimpl"
37
- "google.golang.org/grpc/xds/internal/balancer/outlierdetection"
38
- "google.golang.org/grpc/xds/internal/balancer/priority"
39
- "google.golang.org/grpc/xds/internal/testutils/fakeclient"
40
- "google.golang.org/grpc/xds/internal/xdsclient"
41
- "google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
42
26
)
43
27
44
28
const (
@@ -47,295 +31,13 @@ const (
47
31
testEDSService = "test-eds-service-name"
48
32
testClusterName = "test-cluster-name"
49
33
testClusterName2 = "google_cfe_some-name"
34
+ testBalancerNameFooBar = "foo.bar"
50
35
)
51
36
52
- var (
53
- // A non-empty endpoints update which is expected to be accepted by the EDS
54
- // LB policy.
55
- defaultEndpointsUpdate = xdsresource.EndpointsUpdate {
56
- Localities : []xdsresource.Locality {
57
- {
58
- Endpoints : []xdsresource.Endpoint {{Address : "endpoint1" }},
59
- ID : xdsinternal.LocalityID {Zone : "zone" },
60
- Priority : 1 ,
61
- Weight : 100 ,
62
- },
63
- },
64
- }
65
- )
66
-
67
- func init () {
68
- balancer .Register (bb {})
69
- }
70
-
71
37
type s struct {
72
38
grpctest.Tester
73
-
74
- cleanup func ()
75
- }
76
-
77
- func (ss s ) Teardown (t * testing.T ) {
78
- xdsclient .ClearAllCountersForTesting ()
79
- ss .Tester .Teardown (t )
80
- if ss .cleanup != nil {
81
- ss .cleanup ()
82
- }
83
39
}
84
40
85
41
func Test (t * testing.T ) {
86
42
grpctest .RunSubTests (t , s {})
87
43
}
88
-
89
- const testBalancerNameFooBar = "foo.bar"
90
-
91
- func newNoopTestClientConn () * noopTestClientConn {
92
- return & noopTestClientConn {}
93
- }
94
-
95
- // noopTestClientConn is used in EDS balancer config update tests that only
96
- // cover the config update handling, but not SubConn/load-balancing.
97
- type noopTestClientConn struct {
98
- balancer.ClientConn
99
- }
100
-
101
- func (t * noopTestClientConn ) NewSubConn ([]resolver.Address , balancer.NewSubConnOptions ) (balancer.SubConn , error ) {
102
- return nil , nil
103
- }
104
-
105
- func (noopTestClientConn ) Target () string { return testEDSService }
106
-
107
- type scStateChange struct {
108
- sc balancer.SubConn
109
- state balancer.SubConnState
110
- }
111
-
112
- type fakeChildBalancer struct {
113
- cc balancer.ClientConn
114
- subConnState * testutils.Channel
115
- clientConnState * testutils.Channel
116
- resolverError * testutils.Channel
117
- }
118
-
119
- func (f * fakeChildBalancer ) UpdateClientConnState (state balancer.ClientConnState ) error {
120
- f .clientConnState .Send (state )
121
- return nil
122
- }
123
-
124
- func (f * fakeChildBalancer ) ResolverError (err error ) {
125
- f .resolverError .Send (err )
126
- }
127
-
128
- func (f * fakeChildBalancer ) UpdateSubConnState (sc balancer.SubConn , state balancer.SubConnState ) {
129
- f .subConnState .Send (& scStateChange {sc : sc , state : state })
130
- }
131
-
132
- func (f * fakeChildBalancer ) Close () {}
133
-
134
- func (f * fakeChildBalancer ) ExitIdle () {}
135
-
136
- func (f * fakeChildBalancer ) waitForClientConnStateChangeVerifyBalancerConfig (ctx context.Context , wantCCS balancer.ClientConnState ) error {
137
- ccs , err := f .clientConnState .Receive (ctx )
138
- if err != nil {
139
- return err
140
- }
141
- gotCCS := ccs .(balancer.ClientConnState )
142
- if diff := cmp .Diff (gotCCS , wantCCS , cmpopts .IgnoreFields (balancer.ClientConnState {}, "ResolverState" )); diff != "" {
143
- return fmt .Errorf ("received unexpected ClientConnState, diff (-got +want): %v" , diff )
144
- }
145
- return nil
146
- }
147
-
148
- func (f * fakeChildBalancer ) waitForSubConnStateChange (ctx context.Context , wantState * scStateChange ) error {
149
- val , err := f .subConnState .Receive (ctx )
150
- if err != nil {
151
- return err
152
- }
153
- gotState := val .(* scStateChange )
154
- if ! cmp .Equal (gotState , wantState , cmp .AllowUnexported (scStateChange {})) {
155
- return fmt .Errorf ("got subconnStateChange %v, want %v" , gotState , wantState )
156
- }
157
- return nil
158
- }
159
-
160
- func newFakeChildBalancer (cc balancer.ClientConn ) balancer.Balancer {
161
- return & fakeChildBalancer {
162
- cc : cc ,
163
- subConnState : testutils .NewChannelWithSize (10 ),
164
- clientConnState : testutils .NewChannelWithSize (10 ),
165
- resolverError : testutils .NewChannelWithSize (10 ),
166
- }
167
- }
168
-
169
- type fakeSubConn struct {}
170
-
171
- func (* fakeSubConn ) UpdateAddresses ([]resolver.Address ) { panic ("implement me" ) }
172
- func (* fakeSubConn ) Connect () { panic ("implement me" ) }
173
- func (* fakeSubConn ) GetOrBuildProducer (balancer.ProducerBuilder ) (balancer.Producer , func ()) {
174
- panic ("implement me" )
175
- }
176
-
177
- // waitForNewChildLB makes sure that a new child LB is created by the top-level
178
- // clusterResolverBalancer.
179
- func waitForNewChildLB (ctx context.Context , ch * testutils.Channel ) (* fakeChildBalancer , error ) {
180
- val , err := ch .Receive (ctx )
181
- if err != nil {
182
- return nil , fmt .Errorf ("error when waiting for a new edsLB: %v" , err )
183
- }
184
- return val .(* fakeChildBalancer ), nil
185
- }
186
-
187
- // setup overrides the functions which are used to create the xdsClient and the
188
- // edsLB, creates fake version of them and makes them available on the provided
189
- // channels. The returned cancel function should be called by the test for
190
- // cleanup.
191
- func setup (childLBCh * testutils.Channel ) (* fakeclient.Client , func ()) {
192
- xdsC := fakeclient .NewClientWithName (testBalancerNameFooBar )
193
-
194
- origNewChildBalancer := newChildBalancer
195
- newChildBalancer = func (_ balancer.Builder , cc balancer.ClientConn , _ balancer.BuildOptions ) balancer.Balancer {
196
- childLB := newFakeChildBalancer (cc )
197
- defer func () { childLBCh .Send (childLB ) }()
198
- return childLB
199
- }
200
- return xdsC , func () { newChildBalancer = origNewChildBalancer }
201
- }
202
-
203
- // TestSubConnStateChange verifies if the top-level clusterResolverBalancer passes on
204
- // the subConnState to appropriate child balancer.
205
- func (s ) TestSubConnStateChange (t * testing.T ) {
206
- edsLBCh := testutils .NewChannel ()
207
- xdsC , cleanup := setup (edsLBCh )
208
- defer cleanup ()
209
-
210
- builder := balancer .Get (Name )
211
- edsB := builder .Build (newNoopTestClientConn (), balancer.BuildOptions {})
212
- if edsB == nil {
213
- t .Fatalf ("builder.Build(%s) failed and returned nil" , Name )
214
- }
215
- defer edsB .Close ()
216
-
217
- if err := edsB .UpdateClientConnState (balancer.ClientConnState {
218
- ResolverState : xdsclient .SetClient (resolver.State {}, xdsC ),
219
- BalancerConfig : newLBConfigWithOneEDS (testEDSService ),
220
- }); err != nil {
221
- t .Fatalf ("edsB.UpdateClientConnState() failed: %v" , err )
222
- }
223
-
224
- ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
225
- defer cancel ()
226
- if _ , err := xdsC .WaitForWatchEDS (ctx ); err != nil {
227
- t .Fatalf ("xdsClient.WatchEndpoints failed with error: %v" , err )
228
- }
229
- xdsC .InvokeWatchEDSCallback ("" , defaultEndpointsUpdate , nil )
230
- edsLB , err := waitForNewChildLB (ctx , edsLBCh )
231
- if err != nil {
232
- t .Fatal (err )
233
- }
234
-
235
- fsc := & fakeSubConn {}
236
- state := balancer.SubConnState {ConnectivityState : connectivity .Ready }
237
- edsB .UpdateSubConnState (fsc , state )
238
- if err := edsLB .waitForSubConnStateChange (ctx , & scStateChange {sc : fsc , state : state }); err != nil {
239
- t .Fatal (err )
240
- }
241
- }
242
-
243
- func newLBConfigWithOneEDS (edsServiceName string ) * LBConfig {
244
- return & LBConfig {
245
- DiscoveryMechanisms : []DiscoveryMechanism {{
246
- Cluster : testClusterName ,
247
- Type : DiscoveryMechanismTypeEDS ,
248
- EDSServiceName : edsServiceName ,
249
- }},
250
- xdsLBPolicy : iserviceconfig.BalancerConfig {
251
- Name : "ROUND_ROBIN" ,
252
- Config : nil ,
253
- },
254
- }
255
- }
256
-
257
- func newLBConfigWithOneEDSAndOutlierDetection (edsServiceName string , odCfg outlierdetection.LBConfig ) * LBConfig {
258
- lbCfg := newLBConfigWithOneEDS (edsServiceName )
259
- lbCfg .DiscoveryMechanisms [0 ].outlierDetection = odCfg
260
- return lbCfg
261
- }
262
-
263
- // TestOutlierDetection tests the Balancer Config sent down to the child
264
- // priority balancer when Outlier Detection is turned on. The Priority
265
- // Configuration sent downward should have a top level Outlier Detection Policy
266
- // for each priority.
267
- func (s ) TestOutlierDetection (t * testing.T ) {
268
- edsLBCh := testutils .NewChannel ()
269
- xdsC , cleanup := setup (edsLBCh )
270
- defer cleanup ()
271
- builder := balancer .Get (Name )
272
- edsB := builder .Build (newNoopTestClientConn (), balancer.BuildOptions {})
273
- if edsB == nil {
274
- t .Fatalf ("builder.Build(%s) failed and returned nil" , Name )
275
- }
276
- defer edsB .Close ()
277
-
278
- ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
279
- defer cancel ()
280
-
281
- // Update Cluster Resolver with Client Conn State with Outlier Detection
282
- // configuration present. This is what will be passed down to this balancer,
283
- // as CDS Balancer gets the Cluster Update and converts the Outlier
284
- // Detection data to an Outlier Detection configuration and sends it to this
285
- // level.
286
- if err := edsB .UpdateClientConnState (balancer.ClientConnState {
287
- ResolverState : xdsclient .SetClient (resolver.State {}, xdsC ),
288
- BalancerConfig : newLBConfigWithOneEDSAndOutlierDetection (testEDSService , noopODCfg ),
289
- }); err != nil {
290
- t .Fatal (err )
291
- }
292
- if _ , err := xdsC .WaitForWatchEDS (ctx ); err != nil {
293
- t .Fatalf ("xdsClient.WatchEndpoints failed with error: %v" , err )
294
- }
295
-
296
- // Invoke EDS Callback - causes child balancer to be built and then
297
- // UpdateClientConnState called on it with Outlier Detection as a direct
298
- // child.
299
- xdsC .InvokeWatchEDSCallback ("" , defaultEndpointsUpdate , nil )
300
- edsLB , err := waitForNewChildLB (ctx , edsLBCh )
301
- if err != nil {
302
- t .Fatal (err )
303
- }
304
-
305
- // The priority configuration generated should have Outlier Detection as a
306
- // direct child due to Outlier Detection being turned on.
307
- pCfgWant := & priority.LBConfig {
308
- Children : map [string ]* priority.Child {
309
- "priority-0-0" : {
310
- Config : & iserviceconfig.BalancerConfig {
311
- Name : outlierdetection .Name ,
312
- Config : & outlierdetection.LBConfig {
313
- Interval : iserviceconfig .Duration (10 * time .Second ), // default interval
314
- BaseEjectionTime : iserviceconfig .Duration (30 * time .Second ),
315
- MaxEjectionTime : iserviceconfig .Duration (300 * time .Second ),
316
- MaxEjectionPercent : 10 ,
317
- ChildPolicy : & iserviceconfig.BalancerConfig {
318
- Name : clusterimpl .Name ,
319
- Config : & clusterimpl.LBConfig {
320
- Cluster : testClusterName ,
321
- EDSServiceName : "test-eds-service-name" ,
322
- ChildPolicy : & iserviceconfig.BalancerConfig {
323
- Name : "ROUND_ROBIN" ,
324
- Config : nil ,
325
- },
326
- },
327
- },
328
- },
329
- },
330
- IgnoreReresolutionRequests : true ,
331
- },
332
- },
333
- Priorities : []string {"priority-0-0" },
334
- }
335
-
336
- if err := edsLB .waitForClientConnStateChangeVerifyBalancerConfig (ctx , balancer.ClientConnState {
337
- BalancerConfig : pCfgWant ,
338
- }); err != nil {
339
- t .Fatalf ("EDS impl got unexpected update: %v" , err )
340
- }
341
- }
0 commit comments