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 }