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 }