google.golang.org/grpc@v1.62.1/internal/testutils/xds/fakeserver/server.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 fakeserver provides a fake implementation of the management server.
    20  //
    21  // This package is recommended only for scenarios which cannot be tested using
    22  // the xDS management server (which uses envoy-go-control-plane) provided by the
    23  // `internal/testutils/xds/e2e` package.
    24  package fakeserver
    25  
    26  import (
    27  	"fmt"
    28  	"io"
    29  	"net"
    30  	"time"
    31  
    32  	"google.golang.org/grpc"
    33  	"google.golang.org/grpc/codes"
    34  	"google.golang.org/grpc/internal/testutils"
    35  	"google.golang.org/grpc/status"
    36  	"google.golang.org/protobuf/proto"
    37  
    38  	v3discoverygrpc "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
    39  	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
    40  	v3lrsgrpc "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3"
    41  	v3lrspb "github.com/envoyproxy/go-control-plane/envoy/service/load_stats/v3"
    42  )
    43  
    44  const (
    45  	// TODO: Make this a var or a field in the server if there is a need to use a
    46  	// value other than this default.
    47  	defaultChannelBufferSize = 50
    48  	defaultDialTimeout       = 5 * time.Second
    49  )
    50  
    51  // Request wraps the request protobuf (xds/LRS) and error received by the
    52  // Server in a call to stream.Recv().
    53  type Request struct {
    54  	Req proto.Message
    55  	Err error
    56  }
    57  
    58  // Response wraps the response protobuf (xds/LRS) and error that the Server
    59  // should send out to the client through a call to stream.Send()
    60  type Response struct {
    61  	Resp proto.Message
    62  	Err  error
    63  }
    64  
    65  // Server is a fake implementation of xDS and LRS protocols. It listens on the
    66  // same port for both services and exposes a bunch of channels to send/receive
    67  // messages.
    68  //
    69  // This server is recommended only for scenarios which cannot be tested using
    70  // the xDS management server (which uses envoy-go-control-plane) provided by the
    71  // `internal/testutils/xds/e2e` package.
    72  type Server struct {
    73  	// XDSRequestChan is a channel on which received xDS requests are made
    74  	// available to the users of this Server.
    75  	XDSRequestChan *testutils.Channel
    76  	// XDSResponseChan is a channel on which the Server accepts xDS responses
    77  	// to be sent to the client.
    78  	XDSResponseChan chan *Response
    79  	// LRSRequestChan is a channel on which received LRS requests are made
    80  	// available to the users of this Server.
    81  	LRSRequestChan *testutils.Channel
    82  	// LRSResponseChan is a channel on which the Server accepts the LRS
    83  	// response to be sent to the client.
    84  	LRSResponseChan chan *Response
    85  	// LRSStreamOpenChan is a channel on which the Server sends notifications
    86  	// when a new LRS stream is created.
    87  	LRSStreamOpenChan *testutils.Channel
    88  	// LRSStreamCloseChan is a channel on which the Server sends notifications
    89  	// when an existing LRS stream is closed.
    90  	LRSStreamCloseChan *testutils.Channel
    91  	// NewConnChan is a channel on which the fake server notifies receipt of new
    92  	// connection attempts. Tests can gate on this event before proceeding to
    93  	// other actions which depend on a connection to the fake server being up.
    94  	NewConnChan *testutils.Channel
    95  	// Address is the host:port on which the Server is listening for requests.
    96  	Address string
    97  
    98  	// The underlying fake implementation of xDS and LRS.
    99  	*xdsServerV3
   100  	*lrsServerV3
   101  }
   102  
   103  type wrappedListener struct {
   104  	net.Listener
   105  	server *Server
   106  }
   107  
   108  func (wl *wrappedListener) Accept() (net.Conn, error) {
   109  	c, err := wl.Listener.Accept()
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	wl.server.NewConnChan.Send(struct{}{})
   114  	return c, err
   115  }
   116  
   117  // StartServer makes a new Server and gets it to start listening on the given
   118  // net.Listener. If the given net.Listener is nil, a new one is created on a
   119  // local port for gRPC requests. The returned cancel function should be invoked
   120  // by the caller upon completion of the test.
   121  func StartServer(lis net.Listener) (*Server, func(), error) {
   122  	if lis == nil {
   123  		var err error
   124  		lis, err = net.Listen("tcp", "localhost:0")
   125  		if err != nil {
   126  			return nil, func() {}, fmt.Errorf("net.Listen() failed: %v", err)
   127  		}
   128  	}
   129  
   130  	s := NewServer(lis.Addr().String())
   131  	wp := &wrappedListener{
   132  		Listener: lis,
   133  		server:   s,
   134  	}
   135  
   136  	server := grpc.NewServer()
   137  	v3lrsgrpc.RegisterLoadReportingServiceServer(server, s)
   138  	v3discoverygrpc.RegisterAggregatedDiscoveryServiceServer(server, s)
   139  	go server.Serve(wp)
   140  
   141  	return s, func() { server.Stop() }, nil
   142  }
   143  
   144  // NewServer returns a new instance of Server, set to accept requests on addr.
   145  // It is the responsibility of the caller to register the exported ADS and LRS
   146  // services on an appropriate gRPC server. Most usages should prefer
   147  // StartServer() instead of this.
   148  func NewServer(addr string) *Server {
   149  	s := &Server{
   150  		XDSRequestChan:     testutils.NewChannelWithSize(defaultChannelBufferSize),
   151  		LRSRequestChan:     testutils.NewChannelWithSize(defaultChannelBufferSize),
   152  		NewConnChan:        testutils.NewChannelWithSize(defaultChannelBufferSize),
   153  		XDSResponseChan:    make(chan *Response, defaultChannelBufferSize),
   154  		LRSResponseChan:    make(chan *Response, 1), // The server only ever sends one response.
   155  		LRSStreamOpenChan:  testutils.NewChannelWithSize(defaultChannelBufferSize),
   156  		LRSStreamCloseChan: testutils.NewChannelWithSize(defaultChannelBufferSize),
   157  		Address:            addr,
   158  	}
   159  	s.xdsServerV3 = &xdsServerV3{reqChan: s.XDSRequestChan, respChan: s.XDSResponseChan}
   160  	s.lrsServerV3 = &lrsServerV3{reqChan: s.LRSRequestChan, respChan: s.LRSResponseChan, streamOpenChan: s.LRSStreamOpenChan, streamCloseChan: s.LRSStreamCloseChan}
   161  	return s
   162  }
   163  
   164  type xdsServerV3 struct {
   165  	reqChan  *testutils.Channel
   166  	respChan chan *Response
   167  }
   168  
   169  func (xdsS *xdsServerV3) StreamAggregatedResources(s v3discoverygrpc.AggregatedDiscoveryService_StreamAggregatedResourcesServer) error {
   170  	errCh := make(chan error, 2)
   171  	go func() {
   172  		for {
   173  			req, err := s.Recv()
   174  			if err != nil {
   175  				errCh <- err
   176  				return
   177  			}
   178  			xdsS.reqChan.Send(&Request{req, err})
   179  		}
   180  	}()
   181  	go func() {
   182  		var retErr error
   183  		defer func() {
   184  			errCh <- retErr
   185  		}()
   186  
   187  		for {
   188  			select {
   189  			case r := <-xdsS.respChan:
   190  				if r.Err != nil {
   191  					retErr = r.Err
   192  					return
   193  				}
   194  				if err := s.Send(r.Resp.(*v3discoverypb.DiscoveryResponse)); err != nil {
   195  					retErr = err
   196  					return
   197  				}
   198  			case <-s.Context().Done():
   199  				retErr = s.Context().Err()
   200  				return
   201  			}
   202  		}
   203  	}()
   204  
   205  	if err := <-errCh; err != nil {
   206  		return err
   207  	}
   208  	return nil
   209  }
   210  
   211  func (xdsS *xdsServerV3) DeltaAggregatedResources(v3discoverygrpc.AggregatedDiscoveryService_DeltaAggregatedResourcesServer) error {
   212  	return status.Error(codes.Unimplemented, "")
   213  }
   214  
   215  type lrsServerV3 struct {
   216  	reqChan         *testutils.Channel
   217  	respChan        chan *Response
   218  	streamOpenChan  *testutils.Channel
   219  	streamCloseChan *testutils.Channel
   220  }
   221  
   222  func (lrsS *lrsServerV3) StreamLoadStats(s v3lrsgrpc.LoadReportingService_StreamLoadStatsServer) error {
   223  	lrsS.streamOpenChan.Send(nil)
   224  	defer lrsS.streamCloseChan.Send(nil)
   225  
   226  	req, err := s.Recv()
   227  	lrsS.reqChan.Send(&Request{req, err})
   228  	if err != nil {
   229  		return err
   230  	}
   231  
   232  	select {
   233  	case r := <-lrsS.respChan:
   234  		if r.Err != nil {
   235  			return r.Err
   236  		}
   237  		if err := s.Send(r.Resp.(*v3lrspb.LoadStatsResponse)); err != nil {
   238  			return err
   239  		}
   240  	case <-s.Context().Done():
   241  		return s.Context().Err()
   242  	}
   243  
   244  	for {
   245  		req, err := s.Recv()
   246  		lrsS.reqChan.Send(&Request{req, err})
   247  		if err != nil {
   248  			if err == io.EOF {
   249  				return nil
   250  			}
   251  			return err
   252  		}
   253  	}
   254  }