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 }