github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/balancer/rls/internal/testutils/fakeserver/fakeserver.go (about)

     1  /*
     2   *
     3   * Copyright 2020 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 RouteLookupService,
    20  // to be used in unit tests.
    21  package fakeserver
    22  
    23  import (
    24  	"context"
    25  	"errors"
    26  	"fmt"
    27  	"net"
    28  	"time"
    29  
    30  	grpc "github.com/hxx258456/ccgo/grpc"
    31  	rlsgrpc "github.com/hxx258456/ccgo/grpc/internal/proto/grpc_lookup_v1"
    32  	rlspb "github.com/hxx258456/ccgo/grpc/internal/proto/grpc_lookup_v1"
    33  	"github.com/hxx258456/ccgo/grpc/internal/testutils"
    34  )
    35  
    36  const (
    37  	defaultDialTimeout       = 5 * time.Second
    38  	defaultRPCTimeout        = 5 * time.Second
    39  	defaultChannelBufferSize = 50
    40  )
    41  
    42  // Response wraps the response protobuf (xds/LRS) and error that the Server
    43  // should send out to the client through a call to stream.Send()
    44  type Response struct {
    45  	Resp *rlspb.RouteLookupResponse
    46  	Err  error
    47  }
    48  
    49  // Server is a fake implementation of RLS. It exposes channels to send/receive
    50  // RLS requests and responses.
    51  type Server struct {
    52  	rlsgrpc.UnimplementedRouteLookupServiceServer
    53  	RequestChan  *testutils.Channel
    54  	ResponseChan chan Response
    55  	Address      string
    56  }
    57  
    58  // Start makes a new Server which uses the provided net.Listener. If lis is nil,
    59  // it creates a new net.Listener on a local port. The returned cancel function
    60  // should be invoked by the caller upon completion of the test.
    61  func Start(lis net.Listener, opts ...grpc.ServerOption) (*Server, func(), error) {
    62  	if lis == nil {
    63  		var err error
    64  		lis, err = net.Listen("tcp", "localhost:0")
    65  		if err != nil {
    66  			return nil, func() {}, fmt.Errorf("net.Listen() failed: %v", err)
    67  		}
    68  	}
    69  	s := &Server{
    70  		// Give the channels a buffer size of 1 so that we can setup
    71  		// expectations for one lookup call, without blocking.
    72  		RequestChan:  testutils.NewChannelWithSize(defaultChannelBufferSize),
    73  		ResponseChan: make(chan Response, 1),
    74  		Address:      lis.Addr().String(),
    75  	}
    76  
    77  	server := grpc.NewServer(opts...)
    78  	rlsgrpc.RegisterRouteLookupServiceServer(server, s)
    79  	go server.Serve(lis)
    80  
    81  	return s, func() { server.Stop() }, nil
    82  }
    83  
    84  // RouteLookup implements the RouteLookupService.
    85  func (s *Server) RouteLookup(ctx context.Context, req *rlspb.RouteLookupRequest) (*rlspb.RouteLookupResponse, error) {
    86  	s.RequestChan.Send(req)
    87  
    88  	// The leakchecker fails if we don't exit out of here in a reasonable time.
    89  	timer := time.NewTimer(defaultRPCTimeout)
    90  	select {
    91  	case <-timer.C:
    92  		return nil, errors.New("default RPC timeout exceeded")
    93  	case resp := <-s.ResponseChan:
    94  		timer.Stop()
    95  		return resp.Resp, resp.Err
    96  	}
    97  }
    98  
    99  // ClientConn returns a grpc.ClientConn connected to the fakeServer.
   100  func (s *Server) ClientConn() (*grpc.ClientConn, func(), error) {
   101  	ctx, cancel := context.WithTimeout(context.Background(), defaultDialTimeout)
   102  	defer cancel()
   103  
   104  	cc, err := grpc.DialContext(ctx, s.Address, grpc.WithInsecure(), grpc.WithBlock())
   105  	if err != nil {
   106  		return nil, nil, fmt.Errorf("grpc.DialContext(%s) failed: %v", s.Address, err)
   107  	}
   108  	return cc, func() { cc.Close() }, nil
   109  }