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  }