vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/repltracker/reader_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package repltracker
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  	"time"
    23  
    24  	"vitess.io/vitess/go/test/utils"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/mysql/fakesqldb"
    30  	"vitess.io/vitess/go/sqltypes"
    31  	"vitess.io/vitess/go/vt/dbconfigs"
    32  	"vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv"
    33  
    34  	querypb "vitess.io/vitess/go/vt/proto/query"
    35  )
    36  
    37  // TestReaderReadHeartbeat tests that reading a heartbeat sets the appropriate
    38  // fields on the object.
    39  func TestReaderReadHeartbeat(t *testing.T) {
    40  	db := fakesqldb.New(t)
    41  	defer db.Close()
    42  
    43  	now := time.Now()
    44  	tr := newReader(db, &now)
    45  	defer tr.Close()
    46  
    47  	tr.pool.Open(tr.env.Config().DB.AppWithDB(), tr.env.Config().DB.DbaWithDB(), tr.env.Config().DB.AppDebugWithDB())
    48  
    49  	db.AddQuery(fmt.Sprintf("SELECT ts FROM %s.heartbeat WHERE keyspaceShard='%s'", "_vt", tr.keyspaceShard), &sqltypes.Result{
    50  		Fields: []*querypb.Field{
    51  			{Name: "ts", Type: sqltypes.Int64},
    52  		},
    53  		Rows: [][]sqltypes.Value{{
    54  			sqltypes.NewInt64(now.Add(-10 * time.Second).UnixNano()),
    55  		}},
    56  	})
    57  
    58  	cumulativeLagNs.Reset()
    59  	readErrors.Reset()
    60  	reads.Reset()
    61  
    62  	tr.readHeartbeat()
    63  	lag, err := tr.Status()
    64  
    65  	require.NoError(t, err)
    66  	expectedLag := 10 * time.Second
    67  	assert.Equal(t, expectedLag, lag, "wrong latest lag")
    68  	expectedCumLag := 10 * time.Second.Nanoseconds()
    69  	assert.Equal(t, expectedCumLag, cumulativeLagNs.Get(), "wrong cumulative lag")
    70  	assert.Equal(t, int64(1), reads.Get(), "wrong read count")
    71  	assert.Equal(t, int64(0), readErrors.Get(), "wrong read error count")
    72  	expectedHisto := map[string]int64{
    73  		"0":      int64(0),
    74  		"1ms":    int64(0),
    75  		"10ms":   int64(0),
    76  		"100ms":  int64(0),
    77  		"1s":     int64(0),
    78  		"10s":    int64(1),
    79  		"100s":   int64(0),
    80  		"1000s":  int64(0),
    81  		">1000s": int64(0),
    82  	}
    83  	utils.MustMatch(t, expectedHisto, heartbeatLagNsHistogram.Counts(), "wrong counts in histogram")
    84  }
    85  
    86  // TestReaderCloseSetsCurrentLagToZero tests that when closing the heartbeat reader, the current lag is
    87  // set to zero.
    88  func TestReaderCloseSetsCurrentLagToZero(t *testing.T) {
    89  	db := fakesqldb.New(t)
    90  	defer db.Close()
    91  	tr := newReader(db, nil)
    92  
    93  	db.AddQuery(fmt.Sprintf("SELECT ts FROM %s.heartbeat WHERE keyspaceShard='%s'", "_vt", tr.keyspaceShard), &sqltypes.Result{
    94  		Fields: []*querypb.Field{
    95  			{Name: "ts", Type: sqltypes.Int64},
    96  		},
    97  		Rows: [][]sqltypes.Value{{
    98  			sqltypes.NewInt64(time.Now().Add(-10 * time.Second).UnixNano()),
    99  		}},
   100  	})
   101  
   102  	currentLagNs.Reset()
   103  
   104  	tr.Open()
   105  	time.Sleep(2 * time.Second)
   106  
   107  	assert.Greater(t, currentLagNs.Get(), int64(0), "lag should be greater than zero")
   108  
   109  	tr.Close()
   110  
   111  	assert.Equal(t, int64(0), currentLagNs.Get(), "lag should be be zero after closing the reader.")
   112  }
   113  
   114  // TestReaderReadHeartbeatError tests that we properly account for errors
   115  // encountered in the reading of heartbeat.
   116  func TestReaderReadHeartbeatError(t *testing.T) {
   117  	db := fakesqldb.New(t)
   118  	defer db.Close()
   119  
   120  	now := time.Now()
   121  	tr := newReader(db, &now)
   122  	defer tr.Close()
   123  
   124  	tr.pool.Open(tr.env.Config().DB.AppWithDB(), tr.env.Config().DB.DbaWithDB(), tr.env.Config().DB.AppDebugWithDB())
   125  
   126  	cumulativeLagNs.Reset()
   127  	readErrors.Reset()
   128  
   129  	tr.readHeartbeat()
   130  	lag, err := tr.Status()
   131  
   132  	require.Error(t, err)
   133  	assert.EqualError(t, err, tr.lastKnownError.Error(), "expected error")
   134  	assert.Equal(t, 0*time.Second, lag, "wrong lastKnownLag")
   135  	assert.Equal(t, int64(0), cumulativeLagNs.Get(), "wrong cumulative lag")
   136  	assert.Equal(t, int64(1), readErrors.Get(), "wrong read error count")
   137  }
   138  
   139  func newReader(db *fakesqldb.DB, frozenTime *time.Time) *heartbeatReader {
   140  	config := tabletenv.NewDefaultConfig()
   141  	config.ReplicationTracker.Mode = tabletenv.Heartbeat
   142  	config.ReplicationTracker.HeartbeatIntervalSeconds = 1
   143  	params, _ := db.ConnParams().MysqlParams()
   144  	cp := *params
   145  	dbc := dbconfigs.NewTestDBConfigs(cp, cp, "")
   146  	config.DB = dbc
   147  
   148  	tr := newHeartbeatReader(tabletenv.NewEnv(config, "ReaderTest"))
   149  	tr.keyspaceShard = "test:0"
   150  
   151  	if frozenTime != nil {
   152  		tr.now = func() time.Time {
   153  			return *frozenTime
   154  		}
   155  	}
   156  
   157  	return tr
   158  }