github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/controller/v2_client_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  package controller
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/golang/protobuf/proto"
    27  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    28  	"github.com/hxx258456/ccgo/grpc/resolver"
    29  	"github.com/hxx258456/ccgo/grpc/resolver/manual"
    30  	"github.com/hxx258456/ccgo/grpc/xds/internal/testutils/fakeserver"
    31  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource"
    32  
    33  	_ "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/controller/version/v2" // Register the v2 xDS API client.
    34  )
    35  
    36  // TestV2ClientBackoffAfterRecvError verifies if the v2Client backs off when it
    37  // encounters a Recv error while receiving an LDS response.
    38  func (s) TestV2ClientBackoffAfterRecvError(t *testing.T) {
    39  	fakeServer, cleanup := startServer(t)
    40  	defer cleanup()
    41  
    42  	// Override the v2Client backoff function with this, so that we can verify
    43  	// that a backoff actually was triggered.
    44  	boCh := make(chan int, 1)
    45  	clientBackoff := func(v int) time.Duration {
    46  		boCh <- v
    47  		return 0
    48  	}
    49  
    50  	callbackCh := make(chan struct{})
    51  	v2c, err := newTestController(&testUpdateReceiver{
    52  		f: func(xdsresource.ResourceType, map[string]interface{}, xdsresource.UpdateMetadata) { close(callbackCh) },
    53  	}, fakeServer.Address, goodNodeProto, clientBackoff, nil)
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	defer v2c.Close()
    58  	t.Log("Started xds v2Client...")
    59  
    60  	v2c.AddWatch(xdsresource.ListenerResource, goodLDSTarget1)
    61  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
    62  	defer cancel()
    63  	if _, err := fakeServer.XDSRequestChan.Receive(ctx); err != nil {
    64  		t.Fatalf("Timeout expired when expecting an LDS request")
    65  	}
    66  	t.Log("FakeServer received request...")
    67  
    68  	fakeServer.XDSResponseChan <- &fakeserver.Response{Err: errors.New("RPC error")}
    69  	t.Log("Bad LDS response pushed to fakeServer...")
    70  
    71  	timer := time.NewTimer(defaultTestTimeout)
    72  	select {
    73  	case <-timer.C:
    74  		t.Fatal("Timeout when expecting LDS update")
    75  	case <-boCh:
    76  		timer.Stop()
    77  		t.Log("v2Client backed off before retrying...")
    78  	case <-callbackCh:
    79  		t.Fatal("Received unexpected LDS callback")
    80  	}
    81  
    82  	if _, err := fakeServer.XDSRequestChan.Receive(ctx); err != nil {
    83  		t.Fatalf("Timeout expired when expecting an LDS request")
    84  	}
    85  	t.Log("FakeServer received request after backoff...")
    86  }
    87  
    88  // TestV2ClientRetriesAfterBrokenStream verifies the case where a stream
    89  // encountered a Recv() error, and is expected to send out xDS requests for
    90  // registered watchers once it comes back up again.
    91  func (s) TestV2ClientRetriesAfterBrokenStream(t *testing.T) {
    92  	fakeServer, cleanup := startServer(t)
    93  	defer cleanup()
    94  
    95  	callbackCh := testutils.NewChannel()
    96  	v2c, err := newTestController(&testUpdateReceiver{
    97  		f: func(rType xdsresource.ResourceType, d map[string]interface{}, md xdsresource.UpdateMetadata) {
    98  			if rType == xdsresource.ListenerResource {
    99  				if u, ok := d[goodLDSTarget1]; ok {
   100  					t.Logf("Received LDS callback with ldsUpdate {%+v}", u)
   101  					callbackCh.Send(struct{}{})
   102  				}
   103  			}
   104  		},
   105  	}, fakeServer.Address, goodNodeProto, func(int) time.Duration { return 0 }, nil)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	defer v2c.Close()
   110  	t.Log("Started xds v2Client...")
   111  
   112  	v2c.AddWatch(xdsresource.ListenerResource, goodLDSTarget1)
   113  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   114  	defer cancel()
   115  	if _, err := fakeServer.XDSRequestChan.Receive(ctx); err != nil {
   116  		t.Fatalf("Timeout expired when expecting an LDS request")
   117  	}
   118  	t.Log("FakeServer received request...")
   119  
   120  	fakeServer.XDSResponseChan <- &fakeserver.Response{Resp: goodLDSResponse1}
   121  	t.Log("Good LDS response pushed to fakeServer...")
   122  
   123  	if _, err := callbackCh.Receive(ctx); err != nil {
   124  		t.Fatal("Timeout when expecting LDS update")
   125  	}
   126  
   127  	// Read the ack, so the next request is sent after stream re-creation.
   128  	if _, err := fakeServer.XDSRequestChan.Receive(ctx); err != nil {
   129  		t.Fatalf("Timeout expired when expecting an LDS ACK")
   130  	}
   131  
   132  	fakeServer.XDSResponseChan <- &fakeserver.Response{Err: errors.New("RPC error")}
   133  	t.Log("Bad LDS response pushed to fakeServer...")
   134  
   135  	val, err := fakeServer.XDSRequestChan.Receive(ctx)
   136  	if err != nil {
   137  		t.Fatalf("Timeout expired when expecting LDS update")
   138  	}
   139  	gotRequest := val.(*fakeserver.Request)
   140  	if !proto.Equal(gotRequest.Req, goodLDSRequest) {
   141  		t.Fatalf("gotRequest: %+v, wantRequest: %+v", gotRequest.Req, goodLDSRequest)
   142  	}
   143  }
   144  
   145  // TestV2ClientWatchWithoutStream verifies the case where a watch is started
   146  // when the xds stream is not created. The watcher should not receive any update
   147  // (because there won't be any xds response, and timeout is done at a upper
   148  // level). And when the stream is re-created, the watcher should get future
   149  // updates.
   150  func (s) TestV2ClientWatchWithoutStream(t *testing.T) {
   151  	fakeServer, sCleanup, err := fakeserver.StartServer()
   152  	if err != nil {
   153  		t.Fatalf("Failed to start fake xDS server: %v", err)
   154  	}
   155  	defer sCleanup()
   156  
   157  	const scheme = "xds-client-test-whatever"
   158  	rb := manual.NewBuilderWithScheme(scheme)
   159  	rb.InitialState(resolver.State{Addresses: []resolver.Address{{Addr: "no.such.server"}}})
   160  	resolver.Register(rb)
   161  	defer resolver.UnregisterForTesting(scheme)
   162  
   163  	callbackCh := testutils.NewChannel()
   164  	v2c, err := newTestController(&testUpdateReceiver{
   165  		f: func(rType xdsresource.ResourceType, d map[string]interface{}, md xdsresource.UpdateMetadata) {
   166  			if rType == xdsresource.ListenerResource {
   167  				if u, ok := d[goodLDSTarget1]; ok {
   168  					t.Logf("Received LDS callback with ldsUpdate {%+v}", u)
   169  					callbackCh.Send(u)
   170  				}
   171  			}
   172  		},
   173  	}, scheme+":///whatever", goodNodeProto, func(int) time.Duration { return 0 }, nil)
   174  	if err != nil {
   175  		t.Fatal(err)
   176  	}
   177  	defer v2c.Close()
   178  	t.Log("Started xds v2Client...")
   179  
   180  	// This watch is started when the xds-ClientConn is in Transient Failure,
   181  	// and no xds stream is created.
   182  	v2c.AddWatch(xdsresource.ListenerResource, goodLDSTarget1)
   183  
   184  	// The watcher should receive an update, with a timeout error in it.
   185  	sCtx, sCancel := context.WithTimeout(context.Background(), defaultTestShortTimeout)
   186  	defer sCancel()
   187  	if v, err := callbackCh.Receive(sCtx); err == nil {
   188  		t.Fatalf("Expect an timeout error from watcher, got %v", v)
   189  	}
   190  
   191  	// Send the real server address to the ClientConn, the stream should be
   192  	// created, and the previous watch should be sent.
   193  	rb.UpdateState(resolver.State{
   194  		Addresses: []resolver.Address{{Addr: fakeServer.Address}},
   195  	})
   196  
   197  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   198  	defer cancel()
   199  	if _, err := fakeServer.XDSRequestChan.Receive(ctx); err != nil {
   200  		t.Fatalf("Timeout expired when expecting an LDS request")
   201  	}
   202  	t.Log("FakeServer received request...")
   203  
   204  	fakeServer.XDSResponseChan <- &fakeserver.Response{Resp: goodLDSResponse1}
   205  	t.Log("Good LDS response pushed to fakeServer...")
   206  
   207  	if v, err := callbackCh.Receive(ctx); err != nil {
   208  		t.Fatal("Timeout when expecting LDS update")
   209  	} else if _, ok := v.(xdsresource.ListenerUpdateErrTuple); !ok {
   210  		t.Fatalf("Expect an LDS update from watcher, got %v", v)
   211  	}
   212  }