github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/test/mock/grpc.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package mock 15 16 import ( 17 "context" 18 "sync" 19 20 "github.com/pingcap/log" 21 pb "github.com/pingcap/tiflow/engine/enginepb" 22 "github.com/pingcap/tiflow/pkg/errors" 23 "go.uber.org/zap" 24 "google.golang.org/grpc" 25 ) 26 27 var container *grpcContainer 28 29 func init() { 30 ResetGrpcCtx() 31 } 32 33 type grpcContainer struct { 34 mu sync.Mutex 35 servers map[string]GrpcServer 36 } 37 38 // GrpcServer implements a mock grpc server. 39 type GrpcServer interface { 40 dial() (Conn, error) 41 Stop() 42 } 43 44 type masterServices interface { 45 pb.DiscoveryServer 46 pb.TaskSchedulerServer 47 pb.JobManagerServer 48 } 49 50 type masterServer struct { 51 *baseServer 52 masterServices 53 } 54 55 func (s *masterServer) dial() (Conn, error) { 56 return &masterServerConn{s}, nil 57 } 58 59 type masterServerConn struct { 60 server *masterServer 61 } 62 63 func (s *masterServerConn) Close() error { 64 return nil 65 } 66 67 func (s *masterServerConn) sendRequest(ctx context.Context, req interface{}) (interface{}, error) { 68 switch x := req.(type) { 69 case *pb.RegisterExecutorRequest: 70 return s.server.RegisterExecutor(ctx, x) 71 case *pb.CreateJobRequest: 72 return s.server.CreateJob(ctx, x) 73 case *pb.HeartbeatRequest: 74 return s.server.Heartbeat(ctx, x) 75 case *pb.CancelJobRequest: 76 return s.server.CancelJob(ctx, x) 77 } 78 return nil, errors.New("unknown request") 79 } 80 81 type executorServer struct { 82 *baseServer 83 pb.ExecutorServiceServer 84 } 85 86 type executorServerConn struct { 87 server *executorServer 88 } 89 90 type executorClient struct { 91 conn Conn 92 } 93 94 type baseServer struct { 95 addr string 96 } 97 98 func (s *baseServer) Stop() { 99 container.mu.Lock() 100 defer container.mu.Unlock() 101 _, ok := container.servers[s.addr] 102 log.Info("server is canceled", zap.String("ip", s.addr)) 103 if ok { 104 delete(container.servers, s.addr) 105 } 106 } 107 108 func (s *executorServer) dial() (Conn, error) { 109 return &executorServerConn{s}, nil 110 } 111 112 func (c *executorClient) PreDispatchTask(ctx context.Context, in *pb.PreDispatchTaskRequest, opts ...grpc.CallOption) (*pb.PreDispatchTaskResponse, error) { 113 panic("implement me") 114 } 115 116 func (c *executorClient) ConfirmDispatchTask(ctx context.Context, in *pb.ConfirmDispatchTaskRequest, opts ...grpc.CallOption) (*pb.ConfirmDispatchTaskResponse, error) { 117 panic("implement me") 118 } 119 120 // Close closes executor server conn 121 func (s *executorServerConn) Close() error { 122 return nil 123 } 124 125 // NewExecutorClient returns executor client based on Conn 126 func NewExecutorClient(conn Conn) pb.ExecutorServiceClient { 127 return &executorClient{conn} 128 } 129 130 func (s *executorServerConn) sendRequest(ctx context.Context, req interface{}) (interface{}, error) { 131 switch x := req.(type) { 132 case *pb.PreDispatchTaskRequest: 133 return s.server.PreDispatchTask(ctx, x) 134 case *pb.ConfirmDispatchTaskRequest: 135 return s.server.ConfirmDispatchTask(ctx, x) 136 default: 137 } 138 return nil, errors.New("unknown request") 139 } 140 141 // Dial dials to gRPC server 142 func Dial(addr string) (Conn, error) { 143 container.mu.Lock() 144 defer container.mu.Unlock() 145 server, ok := container.servers[addr] 146 if !ok { 147 return nil, errors.New("no server found") 148 } 149 return server.dial() 150 } 151 152 // NewMasterServer creates a master grpc server and listened the address. 153 // We try to make things simple, so we design the "NewMasterServer" to register only one type of pb server. 154 func NewMasterServer(addr string, server masterServices) (GrpcServer, error) { 155 container.mu.Lock() 156 defer container.mu.Unlock() 157 _, ok := container.servers[addr] 158 if ok { 159 return nil, errors.New("addr " + addr + " has been listened") 160 } 161 newServer := &masterServer{&baseServer{addr}, server} 162 container.servers[addr] = newServer 163 return newServer, nil 164 } 165 166 // NewExecutorServer returns a mock executor gRPC server for given address, if it 167 // doesn't exist, create a new one 168 func NewExecutorServer(addr string, server pb.ExecutorServiceServer) (GrpcServer, error) { 169 container.mu.Lock() 170 defer container.mu.Unlock() 171 _, ok := container.servers[addr] 172 if ok { 173 return nil, errors.New("addr " + addr + " has been listened") 174 } 175 newServer := &executorServer{&baseServer{addr}, server} 176 container.servers[addr] = newServer 177 return newServer, nil 178 } 179 180 // Conn is a simple interface that support send gRPC requests and closeable 181 type Conn interface { 182 Close() error 183 sendRequest(ctx context.Context, req interface{}) (interface{}, error) 184 } 185 186 // ResetGrpcCtx resets grpc servers 187 func ResetGrpcCtx() { 188 container = &grpcContainer{ 189 servers: make(map[string]GrpcServer), 190 } 191 }