github.com/polarismesh/polaris@v1.17.8/plugin/healthchecker/leader/peer_test.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package leader 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "io" 25 "net" 26 "testing" 27 "time" 28 29 "github.com/golang/mock/gomock" 30 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 31 "github.com/polarismesh/specification/source/go/api/v1/service_manage" 32 "github.com/stretchr/testify/assert" 33 "google.golang.org/grpc" 34 35 "github.com/polarismesh/polaris/common/batchjob" 36 "github.com/polarismesh/polaris/common/eventhub" 37 "github.com/polarismesh/polaris/common/utils" 38 "github.com/polarismesh/polaris/plugin" 39 "github.com/polarismesh/polaris/store/mock" 40 ) 41 42 type MockPeerImpl struct { 43 OnServe func(ctx context.Context, p *MockPeerImpl, listenIP string, listenPort uint32) error 44 OnGet func(key string) (*ReadBeatRecord, error) 45 OnPut func(record WriteBeatRecord) error 46 OnDel func(key string) error 47 OnClose func(mp *MockPeerImpl) error 48 OnHost func() string 49 } 50 51 // Initialize 52 func (mp *MockPeerImpl) Initialize(conf Config) {} 53 54 // Serve 55 func (mp *MockPeerImpl) Serve(ctx context.Context, listenIP string, listenPort uint32) error { 56 if mp.OnServe != nil { 57 return mp.OnServe(ctx, mp, listenIP, listenPort) 58 } 59 return nil 60 } 61 62 // Get 63 func (mp *MockPeerImpl) Get(key string) (*ReadBeatRecord, error) { 64 if mp.OnGet == nil { 65 return &ReadBeatRecord{}, nil 66 } 67 return mp.OnGet(key) 68 } 69 70 // Put 71 func (mp *MockPeerImpl) Put(record WriteBeatRecord) error { 72 if mp.OnPut == nil { 73 return nil 74 } 75 return mp.OnPut(record) 76 } 77 78 // Del 79 func (mp *MockPeerImpl) Del(key string) error { 80 if mp.OnDel == nil { 81 return nil 82 } 83 return mp.OnDel(key) 84 } 85 86 // Close 87 func (mp *MockPeerImpl) Close() error { 88 if mp.OnClose == nil { 89 return nil 90 } 91 return mp.OnClose(mp) 92 } 93 94 // Host 95 func (mp *MockPeerImpl) Host() string { 96 if mp.OnHost == nil { 97 return "" 98 } 99 return mp.OnHost() 100 } 101 102 func TestLocalPeer(t *testing.T) { 103 localPeer := newLocalPeer() 104 assert.NotNil(t, localPeer) 105 ctrl := gomock.NewController(t) 106 eventhub.InitEventHub() 107 mockStore := mock.NewMockStore(ctrl) 108 mockStore.EXPECT().StartLeaderElection(gomock.Any()).Return(nil).AnyTimes() 109 checker := &LeaderHealthChecker{ 110 self: NewLocalPeerFunc(), 111 s: mockStore, 112 conf: &Config{ 113 SoltNum: 0, 114 Batch: batchjob.CtrlConfig{ 115 QueueSize: 16, 116 WaitTime: 32 * time.Millisecond, 117 MaxBatchCount: 32, 118 Concurrency: 1, 119 }, 120 }, 121 } 122 err := checker.Initialize(&plugin.ConfigEntry{ 123 Option: map[string]interface{}{}, 124 }) 125 assert.NoError(t, err) 126 127 t.Cleanup(func() { 128 _ = checker.Destroy() 129 eventhub.InitEventHub() 130 ctrl.Finish() 131 }) 132 133 localPeer.Initialize(Config{ 134 SoltNum: 0, 135 Batch: batchjob.CtrlConfig{ 136 Label: "MockLocalPeer", 137 QueueSize: 1024, 138 WaitTime: 32 * time.Millisecond, 139 MaxBatchCount: 32, 140 Concurrency: 1, 141 Handler: func([]batchjob.Future) { panic("not implemented") }, 142 }, 143 }) 144 145 err = localPeer.Serve(context.Background(), checker, "127.0.0.1", 21111) 146 assert.NoError(t, err) 147 148 mockKey := utils.NewUUID() 149 mockVal := time.Now().Unix() 150 151 ret, err := localPeer.Get(mockKey) 152 assert.NoError(t, err) 153 assert.NotNil(t, ret) 154 assert.False(t, ret.Exist) 155 156 err = localPeer.Put(WriteBeatRecord{ 157 Record: RecordValue{ 158 CurTimeSec: mockVal, 159 Count: 0, 160 }, 161 Key: mockKey, 162 }) 163 assert.NoError(t, err) 164 165 ret, err = localPeer.Get(mockKey) 166 assert.NoError(t, err) 167 assert.NotNil(t, ret) 168 assert.True(t, ret.Exist) 169 assert.Equal(t, mockVal, ret.Record.CurTimeSec) 170 171 err = localPeer.Del(mockKey) 172 assert.NoError(t, err) 173 174 ret, err = localPeer.Get(mockKey) 175 assert.NoError(t, err) 176 assert.NotNil(t, ret) 177 assert.False(t, ret.Exist) 178 179 err = localPeer.Close() 180 assert.NoError(t, err) 181 } 182 183 func TestRemotePeer(t *testing.T) { 184 // close old event hub 185 eventhub.InitEventHub() 186 ctrl := gomock.NewController(t) 187 mockStore := mock.NewMockStore(ctrl) 188 mockStore.EXPECT().StartLeaderElection(gomock.Any()).Return(nil) 189 checker := &LeaderHealthChecker{ 190 self: NewLocalPeerFunc(), 191 s: mockStore, 192 conf: &Config{ 193 SoltNum: 0, 194 Batch: batchjob.CtrlConfig{ 195 Label: "MockRemotePeer", 196 QueueSize: 1024, 197 WaitTime: 32 * time.Millisecond, 198 MaxBatchCount: 32, 199 Concurrency: 1, 200 }, 201 }, 202 } 203 204 err := checker.Initialize(&plugin.ConfigEntry{ 205 Option: map[string]interface{}{}, 206 }) 207 assert.NoError(t, err) 208 t.Cleanup(func() { 209 _ = checker.Destroy() 210 eventhub.InitEventHub() 211 ctrl.Finish() 212 }) 213 214 mockPort := uint32(21111) 215 _, err = newMockPolarisGRPCSever(t, mockPort) 216 assert.NoError(t, err) 217 remotePeer := NewRemotePeerFunc() 218 assert.NotNil(t, remotePeer) 219 remotePeer.Initialize(Config{ 220 SoltNum: 0, 221 }) 222 223 err = remotePeer.Serve(context.Background(), checker, "127.0.0.1", mockPort) 224 assert.NoError(t, err) 225 226 mockKey := utils.NewUUID() 227 mockVal := time.Now().Unix() 228 229 ret, err := remotePeer.Get(mockKey) 230 assert.NoError(t, err) 231 assert.NotNil(t, ret) 232 assert.False(t, ret.Exist) 233 234 err = remotePeer.Put(WriteBeatRecord{ 235 Record: RecordValue{ 236 CurTimeSec: mockVal, 237 Count: 0, 238 }, 239 Key: mockKey, 240 }) 241 assert.NoError(t, err) 242 243 ret, err = remotePeer.Get(mockKey) 244 assert.NoError(t, err) 245 assert.NotNil(t, ret) 246 assert.True(t, ret.Exist) 247 assert.True(t, mockVal <= ret.Record.CurTimeSec) 248 249 err = remotePeer.Del(mockKey) 250 assert.NoError(t, err) 251 252 ret, err = remotePeer.Get(mockKey) 253 assert.NoError(t, err) 254 assert.NotNil(t, ret) 255 assert.False(t, ret.Exist) 256 257 err = remotePeer.Close() 258 assert.NoError(t, err) 259 } 260 261 func newMockPolarisGRPCSever(t *testing.T, port uint32) (*MockPolarisGRPCServer, error) { 262 ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) 263 if err != nil { 264 t.Fatal(err) 265 } 266 t.Cleanup(func() { 267 _ = ln.Close() 268 }) 269 ctrl := gomock.NewController(t) 270 eventhub.InitEventHub() 271 t.Cleanup(func() { 272 ctrl.Finish() 273 }) 274 mockStore := mock.NewMockStore(ctrl) 275 mockStore.EXPECT().StartLeaderElection(gomock.Any()).Return(nil) 276 checker := &LeaderHealthChecker{ 277 self: NewLocalPeerFunc(), 278 s: mockStore, 279 conf: &Config{ 280 SoltNum: 0, 281 Batch: batchjob.CtrlConfig{ 282 QueueSize: 16, 283 WaitTime: 32 * time.Millisecond, 284 MaxBatchCount: 32, 285 Concurrency: 1, 286 }, 287 }, 288 } 289 err = checker.Initialize(&plugin.ConfigEntry{ 290 Option: map[string]interface{}{}, 291 }) 292 assert.NoError(t, err) 293 lp := NewLocalPeerFunc().(*LocalPeer) 294 lp.Initialize(Config{ 295 SoltNum: 0, 296 Batch: batchjob.CtrlConfig{ 297 Label: "MockLocalPeer", 298 QueueSize: 1024, 299 WaitTime: 32 * time.Millisecond, 300 MaxBatchCount: 32, 301 Concurrency: 1, 302 Handler: func([]batchjob.Future) { panic("not implemented") }, 303 }, 304 }) 305 306 err = lp.Serve(context.Background(), checker, "127.0.0.1", port) 307 assert.NoError(t, err) 308 svr := &MockPolarisGRPCServer{ 309 peer: lp, 310 } 311 312 server := grpc.NewServer() 313 service_manage.RegisterPolarisGRPCServer(server, svr) 314 service_manage.RegisterPolarisHeartbeatGRPCServer(server, svr) 315 316 t.Cleanup(func() { 317 server.Stop() 318 }) 319 320 go func(t *testing.T) { 321 if err := server.Serve(ln); err != nil { 322 t.Error(err) 323 } 324 }(t) 325 326 return svr, nil 327 } 328 329 // PolarisGRPCServer is the server API for PolarisGRPC service. 330 type MockPolarisGRPCServer struct { 331 peer *LocalPeer 332 } 333 334 // 客户端上报 335 func (ms *MockPolarisGRPCServer) ReportClient(context.Context, 336 *service_manage.Client) (*service_manage.Response, error) { 337 return nil, errors.New("unsupport") 338 } 339 340 // 被调方注册服务实例 341 func (ms *MockPolarisGRPCServer) RegisterInstance(context.Context, 342 *service_manage.Instance) (*service_manage.Response, error) { 343 return nil, errors.New("unsupport") 344 } 345 346 // 被调方反注册服务实例 347 func (ms *MockPolarisGRPCServer) DeregisterInstance(context.Context, 348 *service_manage.Instance) (*service_manage.Response, error) { 349 return nil, errors.New("unsupport") 350 } 351 352 // 统一发现接口 353 func (ms *MockPolarisGRPCServer) Discover(_ service_manage.PolarisGRPC_DiscoverServer) error { 354 return errors.New("unsupport") 355 } 356 357 // 被调方上报心跳 358 func (ms *MockPolarisGRPCServer) Heartbeat(context.Context, 359 *service_manage.Instance) (*service_manage.Response, error) { 360 return nil, errors.New("unsupport") 361 } 362 363 // BatchHeartbeat 批量上报心跳 364 func (ms *MockPolarisGRPCServer) BatchHeartbeat(svr service_manage.PolarisHeartbeatGRPC_BatchHeartbeatServer) error { 365 for { 366 req, err := svr.Recv() 367 if err != nil { 368 if io.EOF == err { 369 return nil 370 } 371 return err 372 } 373 374 heartbeats := req.GetHeartbeats() 375 for i := range heartbeats { 376 ms.peer.Put(WriteBeatRecord{ 377 Record: RecordValue{ 378 CurTimeSec: time.Now().Unix(), 379 }, 380 Key: heartbeats[i].GetInstanceId(), 381 }) 382 } 383 384 if err = svr.Send(&service_manage.HeartbeatsResponse{}); err != nil { 385 return err 386 } 387 } 388 } 389 390 // 批量获取心跳记录 391 func (ms *MockPolarisGRPCServer) BatchGetHeartbeat(_ context.Context, 392 req *service_manage.GetHeartbeatsRequest) (*service_manage.GetHeartbeatsResponse, error) { 393 keys := req.GetInstanceIds() 394 records := make([]*service_manage.HeartbeatRecord, 0, len(keys)) 395 for i := range keys { 396 ret, err := ms.peer.Get(keys[i]) 397 if err != nil { 398 return nil, err 399 } 400 record := &service_manage.HeartbeatRecord{ 401 InstanceId: keys[i], 402 LastHeartbeatSec: ret.Record.CurTimeSec, 403 Exist: ret.Exist, 404 } 405 records = append(records, record) 406 } 407 return &service_manage.GetHeartbeatsResponse{ 408 Records: records, 409 }, nil 410 } 411 412 // 批量删除心跳记录 413 func (ms *MockPolarisGRPCServer) BatchDelHeartbeat(_ context.Context, 414 req *service_manage.DelHeartbeatsRequest) (*service_manage.DelHeartbeatsResponse, error) { 415 keys := req.GetInstanceIds() 416 for i := range keys { 417 if err := ms.peer.Del(keys[i]); err != nil { 418 return nil, err 419 } 420 } 421 return &service_manage.DelHeartbeatsResponse{ 422 Code: uint32(apimodel.Code_ExecuteSuccess), 423 }, nil 424 }