google.golang.org/grpc@v1.72.2/balancer/rls/picker_test.go (about) 1 /* 2 * 3 * Copyright 2021 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 rls 20 21 import ( 22 "context" 23 "errors" 24 "fmt" 25 "testing" 26 "time" 27 28 "google.golang.org/grpc" 29 "google.golang.org/grpc/balancer" 30 "google.golang.org/grpc/codes" 31 "google.golang.org/grpc/credentials/insecure" 32 "google.golang.org/grpc/internal/grpcsync" 33 "google.golang.org/grpc/internal/stubserver" 34 rlstest "google.golang.org/grpc/internal/testutils/rls" 35 "google.golang.org/grpc/internal/testutils/stats" 36 "google.golang.org/grpc/metadata" 37 "google.golang.org/grpc/status" 38 "google.golang.org/protobuf/types/known/durationpb" 39 40 rlspb "google.golang.org/grpc/internal/proto/grpc_lookup_v1" 41 testgrpc "google.golang.org/grpc/interop/grpc_testing" 42 testpb "google.golang.org/grpc/interop/grpc_testing" 43 ) 44 45 // TestNoNonEmptyTargetsReturnsError tests the case where the RLS Server returns 46 // a response with no non empty targets. This should be treated as an Control 47 // Plane RPC failure, and thus fail Data Plane RPC's with an error with the 48 // appropriate information specifying data plane sent a response with no non 49 // empty targets. 50 func (s) TestNoNonEmptyTargetsReturnsError(t *testing.T) { 51 // Setup RLS Server to return a response with an empty target string. 52 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 53 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 54 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{}} 55 }) 56 57 // Register a manual resolver and push the RLS service config through it. 58 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 59 r := startManualResolverWithConfig(t, rlsConfig) 60 61 // Create new client. 62 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 63 if err != nil { 64 t.Fatalf("Failed to create gRPC client: %v", err) 65 } 66 defer cc.Close() 67 68 // Make an RPC and expect it to fail with an error specifying RLS response's 69 // target list does not contain any non empty entries. 70 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 71 defer cancel() 72 makeTestRPCAndVerifyError(ctx, t, cc, codes.Unavailable, errors.New("RLS response's target list does not contain any entries for key")) 73 74 // Make sure an RLS request is sent out. Even though the RLS Server will 75 // return no targets, the request should still hit the server. 76 verifyRLSRequest(t, rlsReqCh, true) 77 } 78 79 // Test verifies the scenario where there is no matching entry in the data cache 80 // and no pending request either, and the ensuing RLS request is throttled. 81 func (s) TestPick_DataCacheMiss_NoPendingEntry_ThrottledWithDefaultTarget(t *testing.T) { 82 // Start an RLS server and set the throttler to always throttle requests. 83 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 84 overrideAdaptiveThrottler(t, alwaysThrottlingThrottler()) 85 86 // Build RLS service config with a default target. 87 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 88 defBackendCh, defBackendAddress := startBackend(t) 89 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 90 91 // Register a manual resolver and push the RLS service config through it. 92 r := startManualResolverWithConfig(t, rlsConfig) 93 94 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 95 if err != nil { 96 t.Fatalf("Failed to create gRPC client: %v", err) 97 } 98 defer cc.Close() 99 100 // Make an RPC and ensure it gets routed to the default target. 101 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 102 defer cancel() 103 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, defBackendCh) 104 105 // Make sure no RLS request is sent out. 106 verifyRLSRequest(t, rlsReqCh, false) 107 } 108 109 // Test verifies the scenario where there is no matching entry in the data cache 110 // and no pending request either, and the ensuing RLS request is throttled. 111 // There is no default target configured in the service config, so the RPC is 112 // expected to fail with an RLS throttled error. 113 func (s) TestPick_DataCacheMiss_NoPendingEntry_ThrottledWithoutDefaultTarget(t *testing.T) { 114 // Start an RLS server and set the throttler to always throttle requests. 115 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 116 overrideAdaptiveThrottler(t, alwaysThrottlingThrottler()) 117 118 // Build an RLS config without a default target. 119 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 120 121 // Register a manual resolver and push the RLS service config through it. 122 r := startManualResolverWithConfig(t, rlsConfig) 123 124 // Create new client. 125 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 126 if err != nil { 127 t.Fatalf("Failed to create gRPC client: %v", err) 128 } 129 defer cc.Close() 130 131 // Make an RPC and expect it to fail with RLS throttled error. 132 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 133 defer cancel() 134 makeTestRPCAndVerifyError(ctx, t, cc, codes.Unavailable, errRLSThrottled) 135 136 // Make sure no RLS request is sent out. 137 verifyRLSRequest(t, rlsReqCh, false) 138 } 139 140 // Test verifies the scenario where there is no matching entry in the data cache 141 // and no pending request either, and the ensuing RLS request is not throttled. 142 // The RLS response does not contain any backends, so the RPC fails with a 143 // unavailable error. 144 func (s) TestPick_DataCacheMiss_NoPendingEntry_NotThrottled(t *testing.T) { 145 // Start an RLS server and set the throttler to never throttle requests. 146 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 147 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 148 149 // Build an RLS config without a default target. 150 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 151 152 // Register a manual resolver and push the RLS service config through it. 153 r := startManualResolverWithConfig(t, rlsConfig) 154 155 // Create new client. 156 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 157 if err != nil { 158 t.Fatalf("Failed to create gRPC client: %v", err) 159 } 160 defer cc.Close() 161 162 // Make an RPC and expect it to fail with deadline exceeded error. We use a 163 // smaller timeout to ensure that the test doesn't run very long. 164 ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 165 defer cancel() 166 makeTestRPCAndVerifyError(ctx, t, cc, codes.Unavailable, errors.New("RLS response's target list does not contain any entries for key")) 167 168 // Make sure an RLS request is sent out. 169 verifyRLSRequest(t, rlsReqCh, true) 170 } 171 172 // Test verifies the scenario where there is no matching entry in the data 173 // cache, but there is a pending request. So, we expect no RLS request to be 174 // sent out. The pick should be queued and not delegated to the default target. 175 func (s) TestPick_DataCacheMiss_PendingEntryExists(t *testing.T) { 176 tests := []struct { 177 name string 178 withDefaultTarget bool 179 }{ 180 { 181 name: "withDefaultTarget", 182 withDefaultTarget: true, 183 }, 184 { 185 name: "withoutDefaultTarget", 186 withDefaultTarget: false, 187 }, 188 } 189 190 for _, test := range tests { 191 t.Run(test.name, func(t *testing.T) { 192 // A unary interceptor which blocks the RouteLookup RPC on the fake 193 // RLS server until the test is done. The first RPC by the client 194 // will cause the LB policy to send out an RLS request. This will 195 // also lead to creation of a pending entry, and further RPCs by the 196 // client should not result in RLS requests being sent out. 197 rlsReqCh := make(chan struct{}, 1) 198 interceptor := func(ctx context.Context, _ any, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (resp any, err error) { 199 rlsReqCh <- struct{}{} 200 <-ctx.Done() 201 return nil, ctx.Err() 202 } 203 204 // Start an RLS server and set the throttler to never throttle. 205 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil, grpc.UnaryInterceptor(interceptor)) 206 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 207 208 // Build RLS service config with an optional default target. 209 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 210 if test.withDefaultTarget { 211 _, defBackendAddress := startBackend(t) 212 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 213 } 214 215 // Register a manual resolver and push the RLS service config 216 // through it. 217 r := startManualResolverWithConfig(t, rlsConfig) 218 219 // Create new client. 220 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 221 if err != nil { 222 t.Fatalf("Failed to create gRPC client: %v", err) 223 } 224 defer cc.Close() 225 226 // Make an RPC that results in the RLS request being sent out. And 227 // since the RLS server is configured to block on the first request, 228 // this RPC will block until its context expires. This ensures that 229 // we have a pending cache entry for the duration of the test. 230 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 231 defer cancel() 232 go func() { 233 client := testgrpc.NewTestServiceClient(cc) 234 client.EmptyCall(ctx, &testpb.Empty{}) 235 }() 236 237 // Make sure an RLS request is sent out. 238 verifyRLSRequest(t, rlsReqCh, true) 239 240 // Make another RPC and expect it to fail the same way. 241 ctx, cancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) 242 defer cancel() 243 makeTestRPCAndVerifyError(ctx, t, cc, codes.DeadlineExceeded, context.DeadlineExceeded) 244 245 // Make sure no RLS request is sent out this time around. 246 verifyRLSRequest(t, rlsReqCh, false) 247 }) 248 } 249 } 250 251 // Test_RLSDefaultTargetPicksMetric tests the default target picks metric. It 252 // configures an RLS Balancer which specifies to route to the default target in 253 // the RLS Configuration, and makes an RPC on a Channel containing this RLS 254 // Balancer. This test then asserts a default target picks metric is emitted, 255 // and target pick or failed pick metric is not emitted. 256 func (s) Test_RLSDefaultTargetPicksMetric(t *testing.T) { 257 // Start an RLS server and set the throttler to always throttle requests. 258 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil) 259 overrideAdaptiveThrottler(t, alwaysThrottlingThrottler()) 260 261 // Build RLS service config with a default target. 262 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 263 defBackendCh, defBackendAddress := startBackend(t) 264 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 265 266 // Register a manual resolver and push the RLS service config through it. 267 r := startManualResolverWithConfig(t, rlsConfig) 268 269 tmr := stats.NewTestMetricsRecorder() 270 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithStatsHandler(tmr)) 271 if err != nil { 272 t.Fatalf("grpc.NewClient() failed: %v", err) 273 } 274 defer cc.Close() 275 276 // Make an RPC and ensure it gets routed to the default target. 277 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 278 defer cancel() 279 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, defBackendCh) 280 281 if got, _ := tmr.Metric("grpc.lb.rls.default_target_picks"); got != 1 { 282 t.Fatalf("Unexpected data for metric %v, got: %v, want: %v", "grpc.lb.rls.default_target_picks", got, 1) 283 } 284 if _, ok := tmr.Metric("grpc.lb.rls.target_picks"); ok { 285 t.Fatalf("Data is present for metric %v", "grpc.lb.rls.target_picks") 286 } 287 if _, ok := tmr.Metric("grpc.lb.rls.failed_picks"); ok { 288 t.Fatalf("Data is present for metric %v", "grpc.lb.rls.failed_picks") 289 } 290 } 291 292 // Test_RLSTargetPicksMetric tests the target picks metric. It configures an RLS 293 // Balancer which specifies to route to a target through a RouteLookupResponse, 294 // and makes an RPC on a Channel containing this RLS Balancer. This test then 295 // asserts a target picks metric is emitted, and default target pick or failed 296 // pick metric is not emitted. 297 func (s) Test_RLSTargetPicksMetric(t *testing.T) { 298 // Start an RLS server and set the throttler to never throttle requests. 299 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil) 300 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 301 302 // Build the RLS config without a default target. 303 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 304 305 // Start a test backend, and setup the fake RLS server to return this as a 306 // target in the RLS response. 307 testBackendCh, testBackendAddress := startBackend(t) 308 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 309 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 310 }) 311 312 // Register a manual resolver and push the RLS service config through it. 313 r := startManualResolverWithConfig(t, rlsConfig) 314 315 tmr := stats.NewTestMetricsRecorder() 316 // Dial the backend. 317 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithStatsHandler(tmr)) 318 if err != nil { 319 t.Fatalf("grpc.NewClient() failed: %v", err) 320 } 321 defer cc.Close() 322 323 // Make an RPC and ensure it gets routed to the test backend. 324 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 325 defer cancel() 326 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 327 if got, _ := tmr.Metric("grpc.lb.rls.target_picks"); got != 1 { 328 t.Fatalf("Unexpected data for metric %v, got: %v, want: %v", "grpc.lb.rls.target_picks", got, 1) 329 } 330 if _, ok := tmr.Metric("grpc.lb.rls.default_target_picks"); ok { 331 t.Fatalf("Data is present for metric %v", "grpc.lb.rls.default_target_picks") 332 } 333 if _, ok := tmr.Metric("grpc.lb.rls.failed_picks"); ok { 334 t.Fatalf("Data is present for metric %v", "grpc.lb.rls.failed_picks") 335 } 336 } 337 338 // Test_RLSFailedPicksMetric tests the failed picks metric. It configures an RLS 339 // Balancer to fail a pick with unavailable, and makes an RPC on a Channel 340 // containing this RLS Balancer. This test then asserts a failed picks metric is 341 // emitted, and default target pick or target pick metric is not emitted. 342 func (s) Test_RLSFailedPicksMetric(t *testing.T) { 343 // Start an RLS server and set the throttler to never throttle requests. 344 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil) 345 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 346 347 // Build an RLS config without a default target. 348 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 349 350 // Register a manual resolver and push the RLS service config through it. 351 r := startManualResolverWithConfig(t, rlsConfig) 352 353 tmr := stats.NewTestMetricsRecorder() 354 // Dial the backend. 355 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithStatsHandler(tmr)) 356 if err != nil { 357 t.Fatalf("grpc.NewClient() failed: %v", err) 358 } 359 defer cc.Close() 360 361 // Make an RPC and expect it to fail with deadline exceeded error. We use a 362 // smaller timeout to ensure that the test doesn't run very long. 363 ctx, cancel := context.WithTimeout(context.Background(), defaultTestShortTimeout) 364 defer cancel() 365 makeTestRPCAndVerifyError(ctx, t, cc, codes.Unavailable, errors.New("RLS response's target list does not contain any entries for key")) 366 367 if got, _ := tmr.Metric("grpc.lb.rls.failed_picks"); got != 1 { 368 t.Fatalf("Unexpected data for metric %v, got: %v, want: %v", "grpc.lb.rls.failed_picks", got, 1) 369 } 370 if _, ok := tmr.Metric("grpc.lb.rls.target_picks"); ok { 371 t.Fatalf("Data is present for metric %v", "grpc.lb.rls.target_picks") 372 } 373 if _, ok := tmr.Metric("grpc.lb.rls.default_target_picks"); ok { 374 t.Fatalf("Data is present for metric %v", "grpc.lb.rls.default_target_picks") 375 } 376 } 377 378 // Test verifies the scenario where there is a matching entry in the data cache 379 // which is valid and there is no pending request. The pick is expected to be 380 // delegated to the child policy. 381 func (s) TestPick_DataCacheHit_NoPendingEntry_ValidEntry(t *testing.T) { 382 // Start an RLS server and set the throttler to never throttle requests. 383 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 384 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 385 386 // Build the RLS config without a default target. 387 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 388 // Start a test backend, and setup the fake RLS server to return this as a 389 // target in the RLS response. 390 testBackendCh, testBackendAddress := startBackend(t) 391 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 392 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 393 }) 394 395 // Register a manual resolver and push the RLS service config through it. 396 r := startManualResolverWithConfig(t, rlsConfig) 397 398 // Create new client. 399 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 400 if err != nil { 401 t.Fatalf("Failed to create gRPC client: %v", err) 402 } 403 defer cc.Close() 404 405 // Make an RPC and ensure it gets routed to the test backend. 406 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 407 defer cancel() 408 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 409 410 // Make sure an RLS request is sent out. 411 verifyRLSRequest(t, rlsReqCh, true) 412 413 // Make another RPC and expect it to find the target in the data cache. 414 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 415 416 // Make sure no RLS request is sent out this time around. 417 verifyRLSRequest(t, rlsReqCh, false) 418 } 419 420 // Test verifies the scenario where there is a matching entry in the data cache 421 // which is valid and there is no pending request. The pick is expected to be 422 // delegated to the child policy. 423 func (s) TestPick_DataCacheHit_NoPendingEntry_ValidEntry_WithHeaderData(t *testing.T) { 424 // Start an RLS server and set the throttler to never throttle requests. 425 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil) 426 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 427 428 // Build the RLS config without a default target. 429 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 430 431 // Start a test backend which expects the header data contents sent from the 432 // RLS server to be part of RPC metadata as X-Google-RLS-Data header. 433 const headerDataContents = "foo,bar,baz" 434 backend := &stubserver.StubServer{ 435 EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) { 436 gotHeaderData := metadata.ValueFromIncomingContext(ctx, "x-google-rls-data") 437 if len(gotHeaderData) != 1 || gotHeaderData[0] != headerDataContents { 438 return nil, fmt.Errorf("got metadata in `X-Google-RLS-Data` is %v, want %s", gotHeaderData, headerDataContents) 439 } 440 return &testpb.Empty{}, nil 441 }, 442 } 443 if err := backend.StartServer(); err != nil { 444 t.Fatalf("Failed to start backend: %v", err) 445 } 446 t.Logf("Started TestService backend at: %q", backend.Address) 447 defer backend.Stop() 448 449 // Setup the fake RLS server to return the above backend as a target in the 450 // RLS response. Also, populate the header data field in the response. 451 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 452 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{ 453 Targets: []string{backend.Address}, 454 HeaderData: headerDataContents, 455 }} 456 }) 457 458 // Register a manual resolver and push the RLS service config through it. 459 r := startManualResolverWithConfig(t, rlsConfig) 460 461 // Create new client. 462 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 463 if err != nil { 464 t.Fatalf("Failed to create gRPC client: %v", err) 465 } 466 defer cc.Close() 467 468 // Make an RPC and ensure it gets routed to the test backend with the header 469 // data sent by the RLS server. 470 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 471 defer cancel() 472 if _, err := testgrpc.NewTestServiceClient(cc).EmptyCall(ctx, &testpb.Empty{}); err != nil { 473 t.Fatalf("EmptyCall() RPC: %v", err) 474 } 475 } 476 477 // Test verifies the scenario where there is a matching entry in the data cache 478 // which is stale and there is no pending request. The pick is expected to be 479 // delegated to the child policy with a proactive cache refresh. 480 func (s) TestPick_DataCacheHit_NoPendingEntry_StaleEntry(t *testing.T) { 481 // We expect the same pick behavior (i.e delegated to the child policy) for 482 // a proactive refresh whether the control channel is throttled or not. 483 tests := []struct { 484 name string 485 throttled bool 486 }{ 487 { 488 name: "throttled", 489 throttled: true, 490 }, 491 { 492 name: "notThrottled", 493 throttled: false, 494 }, 495 } 496 497 for _, test := range tests { 498 t.Run(test.name, func(t *testing.T) { 499 // Start an RLS server and setup the throttler appropriately. 500 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 501 var throttler *fakeThrottler 502 firstRPCDone := grpcsync.NewEvent() 503 if test.throttled { 504 throttler = oneTimeAllowingThrottler(firstRPCDone) 505 overrideAdaptiveThrottler(t, throttler) 506 } else { 507 throttler = neverThrottlingThrottler() 508 overrideAdaptiveThrottler(t, throttler) 509 } 510 511 // Build the RLS config without a default target. Set the stale age 512 // to a very low value to force entries to become stale quickly. 513 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 514 rlsConfig.RouteLookupConfig.MaxAge = durationpb.New(time.Minute) 515 rlsConfig.RouteLookupConfig.StaleAge = durationpb.New(defaultTestShortTimeout) 516 517 // Start a test backend, and setup the fake RLS server to return 518 // this as a target in the RLS response. 519 testBackendCh, testBackendAddress := startBackend(t) 520 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 521 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 522 }) 523 524 // Register a manual resolver and push the RLS service config 525 // through it. 526 r := startManualResolverWithConfig(t, rlsConfig) 527 528 // Create new client. 529 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 530 if err != nil { 531 t.Fatalf("Failed to create gRPC client: %v", err) 532 } 533 defer cc.Close() 534 535 // Make an RPC and ensure it gets routed to the test backend. 536 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 537 defer cancel() 538 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 539 540 // Make sure an RLS request is sent out. 541 verifyRLSRequest(t, rlsReqCh, true) 542 firstRPCDone.Fire() 543 544 // The cache entry has a large maxAge, but a small stateAge. We keep 545 // retrying until the cache entry becomes stale, in which case we expect a 546 // proactive cache refresh. 547 // 548 // If the control channel is not throttled, then we expect an RLS request 549 // to be sent out. If the control channel is throttled, we expect the fake 550 // throttler's channel to be signalled. 551 for { 552 // Make another RPC and expect it to find the target in the data cache. 553 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 554 555 if !test.throttled { 556 select { 557 case <-time.After(defaultTestShortTimeout): 558 // Go back and retry the RPC. 559 case <-rlsReqCh: 560 return 561 } 562 } else { 563 select { 564 case <-time.After(defaultTestShortTimeout): 565 // Go back and retry the RPC. 566 case <-throttler.throttleCh: 567 return 568 } 569 } 570 } 571 }) 572 } 573 } 574 575 // Test verifies scenarios where there is a matching entry in the data cache 576 // which has expired and there is no pending request. 577 func (s) TestPick_DataCacheHit_NoPendingEntry_ExpiredEntry(t *testing.T) { 578 tests := []struct { 579 name string 580 throttled bool 581 withDefaultTarget bool 582 }{ 583 { 584 name: "throttledWithDefaultTarget", 585 throttled: true, 586 withDefaultTarget: true, 587 }, 588 { 589 name: "throttledWithoutDefaultTarget", 590 throttled: true, 591 withDefaultTarget: false, 592 }, 593 { 594 name: "notThrottled", 595 throttled: false, 596 }, 597 } 598 599 for _, test := range tests { 600 t.Run(test.name, func(t *testing.T) { 601 // Start an RLS server and setup the throttler appropriately. 602 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 603 var throttler *fakeThrottler 604 firstRPCDone := grpcsync.NewEvent() 605 if test.throttled { 606 throttler = oneTimeAllowingThrottler(firstRPCDone) 607 overrideAdaptiveThrottler(t, throttler) 608 } else { 609 throttler = neverThrottlingThrottler() 610 overrideAdaptiveThrottler(t, throttler) 611 } 612 613 // Build the RLS config with a very low value for maxAge. This will 614 // ensure that cache entries become invalid very soon. 615 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 616 rlsConfig.RouteLookupConfig.MaxAge = durationpb.New(defaultTestShortTimeout) 617 618 // Start a default backend if needed. 619 var defBackendCh chan struct{} 620 if test.withDefaultTarget { 621 var defBackendAddress string 622 defBackendCh, defBackendAddress = startBackend(t) 623 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 624 } 625 626 // Start a test backend, and setup the fake RLS server to return 627 // this as a target in the RLS response. 628 testBackendCh, testBackendAddress := startBackend(t) 629 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 630 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 631 }) 632 633 // Register a manual resolver and push the RLS service config 634 // through it. 635 r := startManualResolverWithConfig(t, rlsConfig) 636 637 // Create new client. 638 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 639 if err != nil { 640 t.Fatalf("Failed to create gRPC client: %v", err) 641 } 642 defer cc.Close() 643 644 // Make an RPC and ensure it gets routed to the test backend. 645 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 646 defer cancel() 647 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 648 649 // Make sure an RLS request is sent out. 650 verifyRLSRequest(t, rlsReqCh, true) 651 firstRPCDone.Fire() 652 653 // Keep retrying the RPC until the cache entry expires. Expected behavior 654 // is dependent on the scenario being tested. 655 switch { 656 case test.throttled && test.withDefaultTarget: 657 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, defBackendCh) 658 <-throttler.throttleCh 659 case test.throttled && !test.withDefaultTarget: 660 makeTestRPCAndVerifyError(ctx, t, cc, codes.Unavailable, errRLSThrottled) 661 <-throttler.throttleCh 662 case !test.throttled: 663 for { 664 // The backend to which the RPC is routed does not change after the 665 // cache entry expires because the control channel is not throttled. 666 // So, we need to keep retrying until the cache entry expires, at 667 // which point we expect an RLS request to be sent out and the RPC to 668 // get routed to the same testBackend. 669 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 670 select { 671 case <-time.After(defaultTestShortTimeout): 672 // Go back and retry the RPC. 673 case <-rlsReqCh: 674 return 675 } 676 } 677 } 678 }) 679 } 680 } 681 682 // Test verifies scenarios where there is a matching entry in the data cache 683 // which has expired and is in backoff and there is no pending request. 684 func (s) TestPick_DataCacheHit_NoPendingEntry_ExpiredEntryInBackoff(t *testing.T) { 685 tests := []struct { 686 name string 687 withDefaultTarget bool 688 }{ 689 { 690 name: "withDefaultTarget", 691 withDefaultTarget: true, 692 }, 693 { 694 name: "withoutDefaultTarget", 695 withDefaultTarget: false, 696 }, 697 } 698 699 for _, test := range tests { 700 t.Run(test.name, func(t *testing.T) { 701 // Start an RLS server and set the throttler to never throttle requests. 702 rlsServer, rlsReqCh := rlstest.SetupFakeRLSServer(t, nil) 703 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 704 705 // Override the backoff strategy to return a large backoff which 706 // will make sure the date cache entry remains in backoff for the 707 // duration of the test. 708 origBackoffStrategy := defaultBackoffStrategy 709 defaultBackoffStrategy = &fakeBackoffStrategy{backoff: defaultTestTimeout} 710 defer func() { defaultBackoffStrategy = origBackoffStrategy }() 711 712 // Build the RLS config with a very low value for maxAge. This will 713 // ensure that cache entries become invalid very soon. 714 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 715 rlsConfig.RouteLookupConfig.MaxAge = durationpb.New(defaultTestShortTimeout) 716 717 // Start a default backend if needed. 718 var defBackendCh chan struct{} 719 if test.withDefaultTarget { 720 var defBackendAddress string 721 defBackendCh, defBackendAddress = startBackend(t) 722 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 723 } 724 725 // Start a test backend, and set up the fake RLS server to return this as 726 // a target in the RLS response. 727 testBackendCh, testBackendAddress := startBackend(t) 728 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 729 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 730 }) 731 732 // Register a manual resolver and push the RLS service config through it. 733 r := startManualResolverWithConfig(t, rlsConfig) 734 735 // Create new client. 736 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 737 if err != nil { 738 t.Fatalf("Failed to create gRPC client: %v", err) 739 } 740 defer cc.Close() 741 742 // Make an RPC and ensure it gets routed to the test backend. 743 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 744 defer cancel() 745 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 746 747 // Make sure an RLS request is sent out. 748 verifyRLSRequest(t, rlsReqCh, true) 749 750 // Set up the fake RLS server to return errors. This will push the cache 751 // entry into backoff. 752 var rlsLastErr = status.Error(codes.DeadlineExceeded, "last RLS request failed") 753 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 754 return &rlstest.RouteLookupResponse{Err: rlsLastErr} 755 }) 756 757 // Since the RLS server is now configured to return errors, this will push 758 // the cache entry into backoff. The pick will be delegated to the default 759 // backend if one exits, and will fail with the error returned by the RLS 760 // server otherwise. 761 if test.withDefaultTarget { 762 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, defBackendCh) 763 } else { 764 makeTestRPCAndVerifyError(ctx, t, cc, codes.Unavailable, rlsLastErr) 765 } 766 }) 767 } 768 } 769 770 // Test verifies scenarios where there is a matching entry in the data cache 771 // which is stale and there is a pending request. 772 func (s) TestPick_DataCacheHit_PendingEntryExists_StaleEntry(t *testing.T) { 773 tests := []struct { 774 name string 775 withDefaultTarget bool 776 }{ 777 { 778 name: "withDefaultTarget", 779 withDefaultTarget: true, 780 }, 781 { 782 name: "withoutDefaultTarget", 783 withDefaultTarget: false, 784 }, 785 } 786 787 for _, test := range tests { 788 t.Run(test.name, func(t *testing.T) { 789 // A unary interceptor which simply calls the underlying handler 790 // until the first client RPC is done. We want one client RPC to 791 // succeed to ensure that a data cache entry is created. For 792 // subsequent client RPCs which result in RLS requests, this 793 // interceptor blocks until the test's context expires. And since we 794 // configure the RLS LB policy with a really low value for max age, 795 // this allows us to simulate the condition where the it has an 796 // expired entry and a pending entry in the cache. 797 rlsReqCh := make(chan struct{}, 1) 798 firstRPCDone := grpcsync.NewEvent() 799 interceptor := func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { 800 select { 801 case rlsReqCh <- struct{}{}: 802 default: 803 } 804 if firstRPCDone.HasFired() { 805 <-ctx.Done() 806 return nil, ctx.Err() 807 } 808 return handler(ctx, req) 809 } 810 811 // Start an RLS server and set the throttler to never throttle. 812 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil, grpc.UnaryInterceptor(interceptor)) 813 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 814 815 // Build RLS service config with an optional default target. 816 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 817 if test.withDefaultTarget { 818 _, defBackendAddress := startBackend(t) 819 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 820 } 821 822 // Low value for stale age to force entries to become stale quickly. 823 rlsConfig.RouteLookupConfig.MaxAge = durationpb.New(time.Minute) 824 rlsConfig.RouteLookupConfig.StaleAge = durationpb.New(defaultTestShortTimeout) 825 826 // Start a test backend, and setup the fake RLS server to return 827 // this as a target in the RLS response. 828 testBackendCh, testBackendAddress := startBackend(t) 829 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 830 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 831 }) 832 833 // Register a manual resolver and push the RLS service config 834 // through it. 835 r := startManualResolverWithConfig(t, rlsConfig) 836 837 // Create new client. 838 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 839 if err != nil { 840 t.Fatalf("Failed to create gRPC client: %v", err) 841 } 842 defer cc.Close() 843 844 // Make an RPC and ensure it gets routed to the test backend. 845 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 846 defer cancel() 847 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 848 849 // Make sure an RLS request is sent out. 850 verifyRLSRequest(t, rlsReqCh, true) 851 firstRPCDone.Fire() 852 853 // The cache entry has a large maxAge, but a small stateAge. We keep 854 // retrying until the cache entry becomes stale, in which case we expect a 855 // proactive cache refresh. 856 for { 857 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 858 859 select { 860 case <-time.After(defaultTestShortTimeout): 861 // Go back and retry the RPC. 862 case <-rlsReqCh: 863 return 864 } 865 } 866 }) 867 } 868 } 869 870 // Test verifies scenarios where there is a matching entry in the data cache 871 // which is expired and there is a pending request. 872 func (s) TestPick_DataCacheHit_PendingEntryExists_ExpiredEntry(t *testing.T) { 873 tests := []struct { 874 name string 875 withDefaultTarget bool 876 }{ 877 { 878 name: "withDefaultTarget", 879 withDefaultTarget: true, 880 }, 881 { 882 name: "withoutDefaultTarget", 883 withDefaultTarget: false, 884 }, 885 } 886 887 for _, test := range tests { 888 t.Run(test.name, func(t *testing.T) { 889 // A unary interceptor which simply calls the underlying handler 890 // until the first client RPC is done. We want one client RPC to 891 // succeed to ensure that a data cache entry is created. For 892 // subsequent client RPCs which result in RLS requests, this 893 // interceptor blocks until the test's context expires. And since we 894 // configure the RLS LB policy with a really low value for max age, 895 // this allows us to simulate the condition where the it has an 896 // expired entry and a pending entry in the cache. 897 rlsReqCh := make(chan struct{}, 1) 898 firstRPCDone := grpcsync.NewEvent() 899 interceptor := func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { 900 select { 901 case rlsReqCh <- struct{}{}: 902 default: 903 } 904 if firstRPCDone.HasFired() { 905 <-ctx.Done() 906 return nil, ctx.Err() 907 } 908 return handler(ctx, req) 909 } 910 911 // Start an RLS server and set the throttler to never throttle. 912 rlsServer, _ := rlstest.SetupFakeRLSServer(t, nil, grpc.UnaryInterceptor(interceptor)) 913 overrideAdaptiveThrottler(t, neverThrottlingThrottler()) 914 915 // Build RLS service config with an optional default target. 916 rlsConfig := buildBasicRLSConfigWithChildPolicy(t, t.Name(), rlsServer.Address) 917 if test.withDefaultTarget { 918 _, defBackendAddress := startBackend(t) 919 rlsConfig.RouteLookupConfig.DefaultTarget = defBackendAddress 920 } 921 // Set a low value for maxAge to ensure cache entries expire soon. 922 rlsConfig.RouteLookupConfig.MaxAge = durationpb.New(defaultTestShortTimeout) 923 924 // Start a test backend, and setup the fake RLS server to return 925 // this as a target in the RLS response. 926 testBackendCh, testBackendAddress := startBackend(t) 927 rlsServer.SetResponseCallback(func(context.Context, *rlspb.RouteLookupRequest) *rlstest.RouteLookupResponse { 928 return &rlstest.RouteLookupResponse{Resp: &rlspb.RouteLookupResponse{Targets: []string{testBackendAddress}}} 929 }) 930 931 // Register a manual resolver and push the RLS service config 932 // through it. 933 r := startManualResolverWithConfig(t, rlsConfig) 934 935 // Create new client. 936 cc, err := grpc.NewClient(r.Scheme()+":///", grpc.WithResolvers(r), grpc.WithTransportCredentials(insecure.NewCredentials())) 937 if err != nil { 938 t.Fatalf("Failed to create gRPC client: %v", err) 939 } 940 defer cc.Close() 941 942 // Make an RPC and ensure it gets routed to the test backend. 943 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 944 defer cancel() 945 makeTestRPCAndExpectItToReachBackend(ctx, t, cc, testBackendCh) 946 947 // Make sure an RLS request is sent out. 948 verifyRLSRequest(t, rlsReqCh, true) 949 firstRPCDone.Fire() 950 951 // At this point, we have a cache entry with a small maxAge, and the 952 // RLS server is configured to block on further RLS requests. As we 953 // retry the RPC, at some point the cache entry would expire and 954 // force us to send an RLS request which would block on the server, 955 // giving us a pending cache entry for the duration of the test. 956 go func() { 957 for client := testgrpc.NewTestServiceClient(cc); ctx.Err() == nil; <-time.After(defaultTestShortTimeout) { 958 client.EmptyCall(ctx, &testpb.Empty{}) 959 } 960 }() 961 verifyRLSRequest(t, rlsReqCh, true) 962 963 // Another RPC at this point should find the pending entry and be queued. 964 // But since we pass a small deadline, this RPC should fail with a 965 // deadline exceeded error since the pending request does not return until 966 // the test is done. And since we have a pending entry, we expect no RLS 967 // request to be sent out. 968 sCtx, sCancel := context.WithTimeout(ctx, defaultTestShortTimeout) 969 defer sCancel() 970 makeTestRPCAndVerifyError(sCtx, t, cc, codes.DeadlineExceeded, context.DeadlineExceeded) 971 verifyRLSRequest(t, rlsReqCh, false) 972 }) 973 } 974 } 975 976 func TestIsFullMethodNameValid(t *testing.T) { 977 tests := []struct { 978 desc string 979 methodName string 980 want bool 981 }{ 982 { 983 desc: "does not start with a slash", 984 methodName: "service/method", 985 want: false, 986 }, 987 { 988 desc: "does not contain a method", 989 methodName: "/service", 990 want: false, 991 }, 992 { 993 desc: "path has more elements", 994 methodName: "/service/path/to/method", 995 want: false, 996 }, 997 { 998 desc: "valid", 999 methodName: "/service/method", 1000 want: true, 1001 }, 1002 } 1003 1004 for _, test := range tests { 1005 t.Run(test.desc, func(t *testing.T) { 1006 if got := isFullMethodNameValid(test.methodName); got != test.want { 1007 t.Fatalf("isFullMethodNameValid(%q) = %v, want %v", test.methodName, got, test.want) 1008 } 1009 }) 1010 } 1011 } 1012 1013 // Tests the conversion of the child pickers error to the pick result attribute. 1014 func (s) TestChildPickResultError(t *testing.T) { 1015 tests := []struct { 1016 name string 1017 err error 1018 want string 1019 }{ 1020 { 1021 name: "nil", 1022 err: nil, 1023 want: "complete", 1024 }, 1025 { 1026 name: "errNoSubConnAvailable", 1027 err: balancer.ErrNoSubConnAvailable, 1028 want: "queue", 1029 }, 1030 { 1031 name: "status error", 1032 err: status.Error(codes.Unimplemented, "unimplemented"), 1033 want: "drop", 1034 }, 1035 { 1036 name: "other error", 1037 err: errors.New("some error"), 1038 want: "fail", 1039 }, 1040 } 1041 1042 for _, test := range tests { 1043 t.Run(test.name, func(t *testing.T) { 1044 if got := errToPickResult(test.err); got != test.want { 1045 t.Fatalf("errToPickResult(%q) = %v, want %v", test.err, got, test.want) 1046 } 1047 }) 1048 } 1049 }