mirror of https://github.com/grpc/grpc-go.git
				
				
				
			xds/resolver: fix panic when two LDS updates are receives without RDS in between (#4327)
Also confirmed that the LDS updates shouldn't trigger state update without the RDS.
This commit is contained in:
		
							parent
							
								
									493d388ad2
								
							
						
					
					
						commit
						1895da54b0
					
				|  | @ -132,7 +132,15 @@ func (w *serviceUpdateWatcher) handleLDSResp(update xdsclient.ListenerUpdate, er | ||||||
| 		//
 | 		//
 | ||||||
| 		// If the route name did change, then we must wait until the first RDS
 | 		// If the route name did change, then we must wait until the first RDS
 | ||||||
| 		// update before reporting this LDS config.
 | 		// update before reporting this LDS config.
 | ||||||
|  | 		if w.lastUpdate.virtualHost != nil { | ||||||
|  | 			// We want to send an update with the new fields from the new LDS
 | ||||||
|  | 			// (e.g. max stream duration), and old fields from the the previous
 | ||||||
|  | 			// RDS.
 | ||||||
|  | 			//
 | ||||||
|  | 			// But note that this should only happen when virtual host is set,
 | ||||||
|  | 			// which means an RDS was received.
 | ||||||
| 			w.serviceCb(w.lastUpdate, nil) | 			w.serviceCb(w.lastUpdate, nil) | ||||||
|  | 		} | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	w.rdsName = update.RouteConfigName | 	w.rdsName = update.RouteConfigName | ||||||
|  |  | ||||||
|  | @ -1030,6 +1030,48 @@ func (s) TestXDSResolverResourceNotFoundError(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // TestXDSResolverMultipleLDSUpdates tests the case where two LDS updates with
 | ||||||
|  | // the same RDS name to watch are received without an RDS in between. Those LDS
 | ||||||
|  | // updates shouldn't trigger service config update.
 | ||||||
|  | //
 | ||||||
|  | // This test case also makes sure the resolver doesn't panic.
 | ||||||
|  | func (s) TestXDSResolverMultipleLDSUpdates(t *testing.T) { | ||||||
|  | 	xdsC := fakeclient.NewClient() | ||||||
|  | 	xdsR, tcc, cancel := testSetup(t, setupOpts{ | ||||||
|  | 		xdsClientFunc: func() (xdsClientInterface, error) { return xdsC, nil }, | ||||||
|  | 	}) | ||||||
|  | 	defer func() { | ||||||
|  | 		cancel() | ||||||
|  | 		xdsR.Close() | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) | ||||||
|  | 	defer cancel() | ||||||
|  | 	waitForWatchListener(ctx, t, xdsC, targetStr) | ||||||
|  | 	xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr, HTTPFilters: routerFilterList}, nil) | ||||||
|  | 	waitForWatchRouteConfig(ctx, t, xdsC, routeStr) | ||||||
|  | 	defer replaceRandNumGenerator(0)() | ||||||
|  | 
 | ||||||
|  | 	// Send a new LDS update, with the same fields.
 | ||||||
|  | 	xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr, HTTPFilters: routerFilterList}, nil) | ||||||
|  | 	ctx, cancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) | ||||||
|  | 	defer cancel() | ||||||
|  | 	// Should NOT trigger a state update.
 | ||||||
|  | 	gotState, err := tcc.stateCh.Receive(ctx) | ||||||
|  | 	if err == nil { | ||||||
|  | 		t.Fatalf("ClientConn.UpdateState received %v, want timeout error", gotState) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Send a new LDS update, with the same RDS name, but different fields.
 | ||||||
|  | 	xdsC.InvokeWatchListenerCallback(xdsclient.ListenerUpdate{RouteConfigName: routeStr, MaxStreamDuration: time.Second, HTTPFilters: routerFilterList}, nil) | ||||||
|  | 	ctx, cancel = context.WithTimeout(context.Background(), defaultTestShortTimeout) | ||||||
|  | 	defer cancel() | ||||||
|  | 	gotState, err = tcc.stateCh.Receive(ctx) | ||||||
|  | 	if err == nil { | ||||||
|  | 		t.Fatalf("ClientConn.UpdateState received %v, want timeout error", gotState) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type filterBuilder struct { | type filterBuilder struct { | ||||||
| 	httpfilter.Filter // embedded as we do not need to implement registry / parsing in this test.
 | 	httpfilter.Filter // embedded as we do not need to implement registry / parsing in this test.
 | ||||||
| 	path              *[]string | 	path              *[]string | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue