From 95c834a73ce334a18ab12e5db19324700bcdca0e Mon Sep 17 00:00:00 2001 From: Menghan Li Date: Wed, 12 Feb 2020 11:11:21 -0800 Subject: [PATCH] xds: resolver handle good update after getting an error (#3374) --- xds/internal/resolver/xds_resolver.go | 2 +- xds/internal/resolver/xds_resolver_test.go | 47 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/xds/internal/resolver/xds_resolver.go b/xds/internal/resolver/xds_resolver.go index f116eff9..2ac72b2c 100644 --- a/xds/internal/resolver/xds_resolver.go +++ b/xds/internal/resolver/xds_resolver.go @@ -171,7 +171,7 @@ func (r *xdsResolver) run() { case update := <-r.updateCh: if update.err != nil { r.cc.ReportError(update.err) - return + continue } sc := fmt.Sprintf(jsonFormatSC, update.su.Cluster) r.cc.UpdateState(resolver.State{ diff --git a/xds/internal/resolver/xds_resolver_test.go b/xds/internal/resolver/xds_resolver_test.go index 62c4576f..7dbe7167 100644 --- a/xds/internal/resolver/xds_resolver_test.go +++ b/xds/internal/resolver/xds_resolver_test.go @@ -324,3 +324,50 @@ func TestXDSResolverGoodServiceUpdate(t *testing.T) { t.Fatalf("ClientConn.UpdateState received error in service config: %v", rState.ServiceConfig.Err) } } + +// TestXDSResolverUpdates tests the cases where the resolver gets a good update +// after an error, and an error after the good update. +func TestXDSResolverGoodUpdateAfterError(t *testing.T) { + xdsC := fakeclient.NewClient() + xdsR, tcc, cancel := testSetup(t, setupOpts{ + config: &validConfig, + xdsClientFunc: func(_ xdsclient.Options) (xdsClientInterface, error) { return xdsC, nil }, + }) + defer func() { + cancel() + xdsR.Close() + }() + + waitForWatchService(t, xdsC, targetStr) + + // Invoke the watchAPI callback with a bad service update and wait for the + // ReportError method to be called on the ClientConn. + suErr := errors.New("bad serviceupdate") + xdsC.InvokeWatchServiceCallback("", suErr) + if gotErrVal, gotErr := tcc.errorCh.Receive(); gotErr != nil || gotErrVal != suErr { + t.Fatalf("ClientConn.ReportError() received %v, want %v", gotErrVal, suErr) + } + + // Invoke the watchAPI callback with a good service update and wait for the + // UpdateState method to be called on the ClientConn. + xdsC.InvokeWatchServiceCallback(cluster, nil) + gotState, err := tcc.stateCh.Receive() + if err != nil { + t.Fatalf("ClientConn.UpdateState returned error: %v", err) + } + rState := gotState.(resolver.State) + if gotClient := rState.Attributes.Value(xdsinternal.XDSClientID); gotClient != xdsC { + t.Fatalf("ClientConn.UpdateState got xdsClient: %v, want %v", gotClient, xdsC) + } + if err := rState.ServiceConfig.Err; err != nil { + t.Fatalf("ClientConn.UpdateState received error in service config: %v", rState.ServiceConfig.Err) + } + + // Invoke the watchAPI callback with a bad service update and wait for the + // ReportError method to be called on the ClientConn. + suErr2 := errors.New("bad serviceupdate 2") + xdsC.InvokeWatchServiceCallback("", suErr2) + if gotErrVal, gotErr := tcc.errorCh.Receive(); gotErr != nil || gotErrVal != suErr2 { + t.Fatalf("ClientConn.ReportError() received %v, want %v", gotErrVal, suErr2) + } +}