grpc-go/xds/internal/testutils/fakeclient/client.go

205 lines
6.2 KiB
Go

/*
*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package fakeclient provides a fake implementation of an xDS client.
package fakeclient
import (
"sync"
"google.golang.org/grpc/xds/internal/balancer/lrs"
xdsclient "google.golang.org/grpc/xds/internal/client"
"google.golang.org/grpc/xds/internal/testutils"
)
// Client is a fake implementation of an xds client. It exposes a bunch of
// channels to signal the occurrence of various events.
type Client struct {
name string
suWatchCh *testutils.Channel
cdsWatchCh *testutils.Channel
edsWatchCh *testutils.Channel
suCancelCh *testutils.Channel
cdsCancelCh *testutils.Channel
edsCancelCh *testutils.Channel
loadReportCh *testutils.Channel
closeCh *testutils.Channel
mu sync.Mutex
serviceCb func(xdsclient.ServiceUpdate, error)
cdsCb func(xdsclient.ClusterUpdate, error)
edsCb func(xdsclient.EndpointsUpdate, error)
}
// WatchService registers a LDS/RDS watch.
func (xdsC *Client) WatchService(target string, callback func(xdsclient.ServiceUpdate, error)) func() {
xdsC.mu.Lock()
defer xdsC.mu.Unlock()
xdsC.serviceCb = callback
xdsC.suWatchCh.Send(target)
return func() {
xdsC.suCancelCh.Send(nil)
}
}
// WaitForWatchService waits for WatchService to be invoked on this client
// within a reasonable timeout, and returns the serviceName being watched.
func (xdsC *Client) WaitForWatchService() (string, error) {
val, err := xdsC.suWatchCh.Receive()
if err != nil {
return "", err
}
return val.(string), err
}
// InvokeWatchServiceCallback invokes the registered service watch callback.
func (xdsC *Client) InvokeWatchServiceCallback(cluster string, err error) {
xdsC.mu.Lock()
defer xdsC.mu.Unlock()
xdsC.serviceCb(xdsclient.ServiceUpdate{Cluster: cluster}, err)
}
// WatchCluster registers a CDS watch.
func (xdsC *Client) WatchCluster(clusterName string, callback func(xdsclient.ClusterUpdate, error)) func() {
xdsC.mu.Lock()
defer xdsC.mu.Unlock()
xdsC.cdsCb = callback
xdsC.cdsWatchCh.Send(clusterName)
return func() {
xdsC.cdsCancelCh.Send(nil)
}
}
// WaitForWatchCluster waits for WatchCluster to be invoked on this client
// within a reasonable timeout, and returns the clusterName being watched.
func (xdsC *Client) WaitForWatchCluster() (string, error) {
val, err := xdsC.cdsWatchCh.Receive()
if err != nil {
return "", err
}
return val.(string), err
}
// InvokeWatchClusterCallback invokes the registered cdsWatch callback.
func (xdsC *Client) InvokeWatchClusterCallback(update xdsclient.ClusterUpdate, err error) {
xdsC.mu.Lock()
defer xdsC.mu.Unlock()
xdsC.cdsCb(update, err)
}
// WaitForCancelClusterWatch waits for a CDS watch to be cancelled within a
// reasonable timeout, and returns testutils.ErrRecvTimeout otherwise.
func (xdsC *Client) WaitForCancelClusterWatch() error {
_, err := xdsC.cdsCancelCh.Receive()
return err
}
// WatchEndpoints registers an EDS watch for provided clusterName.
func (xdsC *Client) WatchEndpoints(clusterName string, callback func(xdsclient.EndpointsUpdate, error)) (cancel func()) {
xdsC.mu.Lock()
defer xdsC.mu.Unlock()
xdsC.edsCb = callback
xdsC.edsWatchCh.Send(clusterName)
return func() {
xdsC.edsCancelCh.Send(nil)
}
}
// WaitForWatchEDS waits for WatchEndpoints to be invoked on this client within a
// reasonable timeout, and returns the clusterName being watched.
func (xdsC *Client) WaitForWatchEDS() (string, error) {
val, err := xdsC.edsWatchCh.Receive()
if err != nil {
return "", err
}
return val.(string), err
}
// InvokeWatchEDSCallback invokes the registered edsWatch callback.
func (xdsC *Client) InvokeWatchEDSCallback(update xdsclient.EndpointsUpdate, err error) {
xdsC.mu.Lock()
defer xdsC.mu.Unlock()
xdsC.edsCb(update, err)
}
// ReportLoadArgs wraps the arguments passed to ReportLoad.
type ReportLoadArgs struct {
// Server is the name of the server to which the load is reported.
Server string
// Cluster is the name of the cluster for which load is reported.
Cluster string
}
// ReportLoad starts reporting load about clusterName to server.
func (xdsC *Client) ReportLoad(server string, clusterName string, loadStore lrs.Store) (cancel func()) {
xdsC.loadReportCh.Send(ReportLoadArgs{Server: server, Cluster: clusterName})
return func() {}
}
// WaitForReportLoad waits for ReportLoad to be invoked on this client within a
// reasonable timeout, and returns the arguments passed to it.
func (xdsC *Client) WaitForReportLoad() (ReportLoadArgs, error) {
val, err := xdsC.loadReportCh.Receive()
return val.(ReportLoadArgs), err
}
// Close closes the xds client.
func (xdsC *Client) Close() {
xdsC.closeCh.Send(nil)
}
// WaitForClose waits for Close to be invoked on this client within a
// reasonable timeout, and returns testutils.ErrRecvTimeout otherwise.
func (xdsC *Client) WaitForClose() error {
_, err := xdsC.closeCh.Receive()
return err
}
// Name returns the name of the xds client.
func (xdsC *Client) Name() string {
return xdsC.name
}
// NewClient returns a new fake xds client.
func NewClient() *Client {
return NewClientWithName("")
}
// NewClientWithName returns a new fake xds client with the provided name. This
// is used in cases where multiple clients are created in the tests and we need
// to make sure the client is created for the expected balancer name.
func NewClientWithName(name string) *Client {
return &Client{
name: name,
suWatchCh: testutils.NewChannel(),
cdsWatchCh: testutils.NewChannel(),
edsWatchCh: testutils.NewChannel(),
suCancelCh: testutils.NewChannel(),
cdsCancelCh: testutils.NewChannel(),
edsCancelCh: testutils.NewChannel(),
loadReportCh: testutils.NewChannel(),
closeCh: testutils.NewChannel(),
}
}