gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/testutils/fakeclient/client.go (about) 1 /* 2 * 3 * Copyright 2019 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 fakeclient provides a fake implementation of an xDS client. 20 package fakeclient 21 22 import ( 23 "context" 24 25 "gitee.com/ks-custle/core-gm/grpc/internal/grpcsync" 26 "gitee.com/ks-custle/core-gm/grpc/internal/testutils" 27 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient" 28 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/bootstrap" 29 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/load" 30 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource" 31 ) 32 33 // Client is a fake implementation of an xds client. It exposes a bunch of 34 // channels to signal the occurrence of various events. 35 type Client struct { 36 // Embed XDSClient so this fake client implements the interface, but it's 37 // never set (it's always nil). This may cause nil panic since not all the 38 // methods are implemented. 39 xdsclient.XDSClient 40 41 name string 42 ldsWatchCh *testutils.Channel 43 rdsWatchCh *testutils.Channel 44 cdsWatchCh *testutils.Channel 45 edsWatchCh *testutils.Channel 46 ldsCancelCh *testutils.Channel 47 rdsCancelCh *testutils.Channel 48 cdsCancelCh *testutils.Channel 49 edsCancelCh *testutils.Channel 50 loadReportCh *testutils.Channel 51 lrsCancelCh *testutils.Channel 52 loadStore *load.Store 53 bootstrapCfg *bootstrap.Config 54 55 ldsCb func(xdsresource.ListenerUpdate, error) 56 rdsCbs map[string]func(xdsresource.RouteConfigUpdate, error) 57 cdsCbs map[string]func(xdsresource.ClusterUpdate, error) 58 edsCbs map[string]func(xdsresource.EndpointsUpdate, error) 59 60 Closed *grpcsync.Event // fired when Close is called. 61 } 62 63 // WatchListener registers a LDS watch. 64 func (xdsC *Client) WatchListener(serviceName string, callback func(xdsresource.ListenerUpdate, error)) func() { 65 xdsC.ldsCb = callback 66 xdsC.ldsWatchCh.Send(serviceName) 67 return func() { 68 xdsC.ldsCancelCh.Send(nil) 69 } 70 } 71 72 // WaitForWatchListener waits for WatchCluster to be invoked on this client and 73 // returns the serviceName being watched. 74 func (xdsC *Client) WaitForWatchListener(ctx context.Context) (string, error) { 75 val, err := xdsC.ldsWatchCh.Receive(ctx) 76 if err != nil { 77 return "", err 78 } 79 return val.(string), err 80 } 81 82 // InvokeWatchListenerCallback invokes the registered ldsWatch callback. 83 // 84 // Not thread safe with WatchListener. Only call this after 85 // WaitForWatchListener. 86 func (xdsC *Client) InvokeWatchListenerCallback(update xdsresource.ListenerUpdate, err error) { 87 xdsC.ldsCb(update, err) 88 } 89 90 // WaitForCancelListenerWatch waits for a LDS watch to be cancelled and returns 91 // context.DeadlineExceeded otherwise. 92 func (xdsC *Client) WaitForCancelListenerWatch(ctx context.Context) error { 93 _, err := xdsC.ldsCancelCh.Receive(ctx) 94 return err 95 } 96 97 // WatchRouteConfig registers a RDS watch. 98 func (xdsC *Client) WatchRouteConfig(routeName string, callback func(xdsresource.RouteConfigUpdate, error)) func() { 99 xdsC.rdsCbs[routeName] = callback 100 xdsC.rdsWatchCh.Send(routeName) 101 return func() { 102 xdsC.rdsCancelCh.Send(routeName) 103 } 104 } 105 106 // WaitForWatchRouteConfig waits for WatchCluster to be invoked on this client and 107 // returns the routeName being watched. 108 func (xdsC *Client) WaitForWatchRouteConfig(ctx context.Context) (string, error) { 109 val, err := xdsC.rdsWatchCh.Receive(ctx) 110 if err != nil { 111 return "", err 112 } 113 return val.(string), err 114 } 115 116 // InvokeWatchRouteConfigCallback invokes the registered rdsWatch callback. 117 // 118 // Not thread safe with WatchRouteConfig. Only call this after 119 // WaitForWatchRouteConfig. 120 func (xdsC *Client) InvokeWatchRouteConfigCallback(name string, update xdsresource.RouteConfigUpdate, err error) { 121 if len(xdsC.rdsCbs) != 1 { 122 xdsC.rdsCbs[name](update, err) 123 return 124 } 125 // Keeps functionality with previous usage of this on client side, if single 126 // callback call that callback. 127 var routeName string 128 for route := range xdsC.rdsCbs { 129 routeName = route 130 } 131 xdsC.rdsCbs[routeName](update, err) 132 } 133 134 // WaitForCancelRouteConfigWatch waits for a RDS watch to be cancelled and returns 135 // context.DeadlineExceeded otherwise. 136 func (xdsC *Client) WaitForCancelRouteConfigWatch(ctx context.Context) (string, error) { 137 val, err := xdsC.rdsCancelCh.Receive(ctx) 138 if err != nil { 139 return "", err 140 } 141 return val.(string), err 142 } 143 144 // WatchCluster registers a CDS watch. 145 func (xdsC *Client) WatchCluster(clusterName string, callback func(xdsresource.ClusterUpdate, error)) func() { 146 // Due to the tree like structure of aggregate clusters, there can be multiple callbacks persisted for each cluster 147 // node. However, the client doesn't care about the parent child relationship between the nodes, only that it invokes 148 // the right callback for a particular cluster. 149 xdsC.cdsCbs[clusterName] = callback 150 xdsC.cdsWatchCh.Send(clusterName) 151 return func() { 152 xdsC.cdsCancelCh.Send(clusterName) 153 } 154 } 155 156 // WaitForWatchCluster waits for WatchCluster to be invoked on this client and 157 // returns the clusterName being watched. 158 func (xdsC *Client) WaitForWatchCluster(ctx context.Context) (string, error) { 159 val, err := xdsC.cdsWatchCh.Receive(ctx) 160 if err != nil { 161 return "", err 162 } 163 return val.(string), err 164 } 165 166 // InvokeWatchClusterCallback invokes the registered cdsWatch callback. 167 // 168 // Not thread safe with WatchCluster. Only call this after 169 // WaitForWatchCluster. 170 func (xdsC *Client) InvokeWatchClusterCallback(update xdsresource.ClusterUpdate, err error) { 171 // Keeps functionality with previous usage of this, if single callback call that callback. 172 if len(xdsC.cdsCbs) == 1 { 173 var clusterName string 174 for cluster := range xdsC.cdsCbs { 175 clusterName = cluster 176 } 177 xdsC.cdsCbs[clusterName](update, err) 178 } else { 179 // Have what callback you call with the update determined by the service name in the ClusterUpdate. Left up to the 180 // caller to make sure the cluster update matches with a persisted callback. 181 xdsC.cdsCbs[update.ClusterName](update, err) 182 } 183 } 184 185 // WaitForCancelClusterWatch waits for a CDS watch to be cancelled and returns 186 // context.DeadlineExceeded otherwise. 187 func (xdsC *Client) WaitForCancelClusterWatch(ctx context.Context) (string, error) { 188 clusterNameReceived, err := xdsC.cdsCancelCh.Receive(ctx) 189 if err != nil { 190 return "", err 191 } 192 return clusterNameReceived.(string), err 193 } 194 195 // WatchEndpoints registers an EDS watch for provided clusterName. 196 func (xdsC *Client) WatchEndpoints(clusterName string, callback func(xdsresource.EndpointsUpdate, error)) (cancel func()) { 197 xdsC.edsCbs[clusterName] = callback 198 xdsC.edsWatchCh.Send(clusterName) 199 return func() { 200 xdsC.edsCancelCh.Send(clusterName) 201 } 202 } 203 204 // WaitForWatchEDS waits for WatchEndpoints to be invoked on this client and 205 // returns the clusterName being watched. 206 func (xdsC *Client) WaitForWatchEDS(ctx context.Context) (string, error) { 207 val, err := xdsC.edsWatchCh.Receive(ctx) 208 if err != nil { 209 return "", err 210 } 211 return val.(string), err 212 } 213 214 // InvokeWatchEDSCallback invokes the registered edsWatch callback. 215 // 216 // Not thread safe with WatchEndpoints. Only call this after 217 // WaitForWatchEDS. 218 func (xdsC *Client) InvokeWatchEDSCallback(name string, update xdsresource.EndpointsUpdate, err error) { 219 if len(xdsC.edsCbs) != 1 { 220 // This may panic if name isn't found. But it's fine for tests. 221 xdsC.edsCbs[name](update, err) 222 return 223 } 224 // Keeps functionality with previous usage of this, if single callback call 225 // that callback. 226 for n := range xdsC.edsCbs { 227 name = n 228 } 229 xdsC.edsCbs[name](update, err) 230 } 231 232 // WaitForCancelEDSWatch waits for a EDS watch to be cancelled and returns 233 // context.DeadlineExceeded otherwise. 234 func (xdsC *Client) WaitForCancelEDSWatch(ctx context.Context) (string, error) { 235 edsNameReceived, err := xdsC.edsCancelCh.Receive(ctx) 236 if err != nil { 237 return "", err 238 } 239 return edsNameReceived.(string), err 240 } 241 242 // ReportLoadArgs wraps the arguments passed to ReportLoad. 243 type ReportLoadArgs struct { 244 // Server is the name of the server to which the load is reported. 245 Server string 246 } 247 248 // ReportLoad starts reporting load about clusterName to server. 249 func (xdsC *Client) ReportLoad(server string) (loadStore *load.Store, cancel func()) { 250 xdsC.loadReportCh.Send(ReportLoadArgs{Server: server}) 251 return xdsC.loadStore, func() { 252 xdsC.lrsCancelCh.Send(nil) 253 } 254 } 255 256 // WaitForCancelReportLoad waits for a load report to be cancelled and returns 257 // context.DeadlineExceeded otherwise. 258 func (xdsC *Client) WaitForCancelReportLoad(ctx context.Context) error { 259 _, err := xdsC.lrsCancelCh.Receive(ctx) 260 return err 261 } 262 263 // LoadStore returns the underlying load data store. 264 func (xdsC *Client) LoadStore() *load.Store { 265 return xdsC.loadStore 266 } 267 268 // WaitForReportLoad waits for ReportLoad to be invoked on this client and 269 // returns the arguments passed to it. 270 func (xdsC *Client) WaitForReportLoad(ctx context.Context) (ReportLoadArgs, error) { 271 val, err := xdsC.loadReportCh.Receive(ctx) 272 if err != nil { 273 return ReportLoadArgs{}, err 274 } 275 return val.(ReportLoadArgs), nil 276 } 277 278 // Close fires xdsC.Closed, indicating it was called. 279 func (xdsC *Client) Close() { 280 xdsC.Closed.Fire() 281 } 282 283 // BootstrapConfig returns the bootstrap config. 284 func (xdsC *Client) BootstrapConfig() *bootstrap.Config { 285 return xdsC.bootstrapCfg 286 } 287 288 // SetBootstrapConfig updates the bootstrap config. 289 func (xdsC *Client) SetBootstrapConfig(cfg *bootstrap.Config) { 290 xdsC.bootstrapCfg = cfg 291 } 292 293 // Name returns the name of the xds client. 294 func (xdsC *Client) Name() string { 295 return xdsC.name 296 } 297 298 // NewClient returns a new fake xds client. 299 func NewClient() *Client { 300 return NewClientWithName("") 301 } 302 303 // NewClientWithName returns a new fake xds client with the provided name. This 304 // is used in cases where multiple clients are created in the tests and we need 305 // to make sure the client is created for the expected balancer name. 306 func NewClientWithName(name string) *Client { 307 return &Client{ 308 name: name, 309 ldsWatchCh: testutils.NewChannelWithSize(10), 310 rdsWatchCh: testutils.NewChannelWithSize(10), 311 cdsWatchCh: testutils.NewChannelWithSize(10), 312 edsWatchCh: testutils.NewChannelWithSize(10), 313 ldsCancelCh: testutils.NewChannelWithSize(10), 314 rdsCancelCh: testutils.NewChannelWithSize(10), 315 cdsCancelCh: testutils.NewChannelWithSize(10), 316 edsCancelCh: testutils.NewChannelWithSize(10), 317 loadReportCh: testutils.NewChannel(), 318 lrsCancelCh: testutils.NewChannel(), 319 loadStore: load.NewStore(), 320 bootstrapCfg: &bootstrap.Config{ClientDefaultListenerResourceNameTemplate: "%s"}, 321 rdsCbs: make(map[string]func(xdsresource.RouteConfigUpdate, error)), 322 cdsCbs: make(map[string]func(xdsresource.ClusterUpdate, error)), 323 edsCbs: make(map[string]func(xdsresource.EndpointsUpdate, error)), 324 Closed: grpcsync.NewEvent(), 325 } 326 }