github.com/polarismesh/polaris@v1.17.8/plugin/healthchecker/redis/checker_redis_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 heartbeatredis
    19  
    20  import (
    21  	"context"
    22  	"sync/atomic"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	"github.com/polarismesh/polaris/common/redispool"
    29  	commontime "github.com/polarismesh/polaris/common/time"
    30  	"github.com/polarismesh/polaris/plugin"
    31  )
    32  
    33  type mockPool struct {
    34  	setValues      map[string]map[string]bool
    35  	itemValues     map[string]string
    36  	compatible     bool
    37  	recoverTimeSec int64
    38  }
    39  
    40  // Start 启动ckv连接池工作
    41  func (m *mockPool) Start() {
    42  	m.setValues = make(map[string]map[string]bool)
    43  	m.itemValues = make(map[string]string)
    44  }
    45  
    46  // Sdd 使用连接池,向redis发起Sdd请求
    47  func (m *mockPool) Sdd(id string, members []string) *redispool.Resp {
    48  	values, ok := m.setValues[id]
    49  	if !ok {
    50  		values = make(map[string]bool)
    51  		m.setValues[id] = values
    52  	}
    53  	for _, member := range members {
    54  		values[member] = true
    55  	}
    56  	return &redispool.Resp{Compatible: m.compatible}
    57  }
    58  
    59  // Srem 使用连接池,向redis发起Srem请求
    60  func (m *mockPool) Srem(id string, members []string) *redispool.Resp {
    61  	values, ok := m.setValues[id]
    62  	if ok {
    63  		for _, member := range members {
    64  			delete(values, member)
    65  		}
    66  	}
    67  	return &redispool.Resp{Compatible: m.compatible}
    68  }
    69  
    70  // Get 使用连接池,向redis发起Get请求
    71  func (m *mockPool) Get(id string) *redispool.Resp {
    72  	value, ok := m.itemValues[id]
    73  	return &redispool.Resp{
    74  		Value:      value,
    75  		Exists:     ok,
    76  		Compatible: m.compatible,
    77  	}
    78  }
    79  
    80  // Set 使用连接池,向redis发起Set请求
    81  func (m *mockPool) Set(id string, redisObj redispool.RedisObject) *redispool.Resp {
    82  	value := redisObj.Serialize(m.compatible)
    83  	m.itemValues[id] = value
    84  	return &redispool.Resp{
    85  		Value:      value,
    86  		Exists:     true,
    87  		Compatible: m.compatible,
    88  	}
    89  }
    90  
    91  // Del 使用连接池,向redis发起Del请求
    92  func (m *mockPool) Del(id string) *redispool.Resp {
    93  	delete(m.itemValues, id)
    94  	return &redispool.Resp{
    95  		Exists:     true,
    96  		Compatible: m.compatible,
    97  	}
    98  }
    99  
   100  // RecoverTimeSec the time second record when recover
   101  func (m *mockPool) RecoverTimeSec() int64 {
   102  	return m.recoverTimeSec
   103  }
   104  
   105  func TestReportAndCheck(t *testing.T) {
   106  	pool := &mockPool{}
   107  	checker := &RedisHealthChecker{
   108  		hbPool:    pool,
   109  		checkPool: pool,
   110  	}
   111  	checker.hbPool.Start()
   112  	checker.checkPool.Start()
   113  
   114  	startTime := commontime.CurrentMillisecond() / 1000
   115  	instanceId := "testId"
   116  	host := "localhost"
   117  	var count int64
   118  	var port uint32 = 8888
   119  	reportReq := &plugin.ReportRequest{
   120  		QueryRequest: plugin.QueryRequest{
   121  			InstanceId: instanceId,
   122  			Host:       host,
   123  			Port:       port,
   124  		},
   125  		LocalHost:  "127.0.0.1",
   126  		CurTimeSec: startTime,
   127  		Count:      atomic.AddInt64(&count, 1),
   128  	}
   129  	err := checker.Report(context.Background(), reportReq)
   130  	assert.Nil(t, err)
   131  
   132  	queryResp, err := checker.Query(context.Background(), &reportReq.QueryRequest)
   133  	assert.Nil(t, err)
   134  	assert.Equal(t, reportReq.CurTimeSec, queryResp.LastHeartbeatSec)
   135  
   136  	// after 3 seconds
   137  	curTimeSec := startTime + 3
   138  	checkReq := &plugin.CheckRequest{
   139  		QueryRequest: plugin.QueryRequest{
   140  			InstanceId: instanceId,
   141  			Host:       host,
   142  			Port:       port,
   143  			Healthy:    true,
   144  		},
   145  		ExpireDurationSec: 2,
   146  		CurTimeSec: func() int64 {
   147  			return curTimeSec
   148  		},
   149  	}
   150  	resp, err := checker.Check(checkReq)
   151  	assert.Nil(t, err)
   152  	assert.False(t, resp.StayUnchanged)
   153  	assert.False(t, resp.Healthy)
   154  
   155  	reportReq.CurTimeSec = curTimeSec
   156  	reportReq.Count = atomic.AddInt64(&count, 1)
   157  	err = checker.Report(context.Background(), reportReq)
   158  	assert.Nil(t, err)
   159  
   160  	time.Sleep(3 * time.Second)
   161  	checker.Suspend()
   162  	startTime = commontime.CurrentMillisecond() / 1000
   163  	reportReq.CurTimeSec = startTime
   164  	reportReq.Count = atomic.AddInt64(&count, 1)
   165  	err = checker.Report(context.Background(), reportReq)
   166  	assert.Nil(t, err)
   167  
   168  	checkReq = &plugin.CheckRequest{
   169  		QueryRequest: plugin.QueryRequest{
   170  			InstanceId: instanceId,
   171  			Host:       host,
   172  			Port:       port,
   173  			Healthy:    true,
   174  		},
   175  		ExpireDurationSec: 2,
   176  		CurTimeSec: func() int64 {
   177  			return startTime
   178  		},
   179  	}
   180  	resp, err = checker.Check(checkReq)
   181  	assert.Nil(t, err)
   182  	assert.True(t, resp.StayUnchanged)
   183  
   184  	// after 4 seconds
   185  	time.Sleep(4 * time.Second)
   186  	checkReq = &plugin.CheckRequest{
   187  		QueryRequest: plugin.QueryRequest{
   188  			InstanceId: instanceId,
   189  			Host:       host,
   190  			Port:       port,
   191  			Healthy:    true,
   192  		},
   193  		ExpireDurationSec: 2,
   194  		CurTimeSec: func() int64 {
   195  			return commontime.CurrentMillisecond() / 1000
   196  		},
   197  	}
   198  	resp, err = checker.Check(checkReq)
   199  	assert.Nil(t, err)
   200  	assert.False(t, resp.StayUnchanged)
   201  	assert.False(t, resp.Healthy)
   202  }