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 }