vitess.io/vitess@v0.16.2/go/vt/vttablet/endtoend/connkilling/connkiller_test.go (about) 1 /* 2 Copyright 2020 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 /* 18 All tests in this package come with a three second time out for OLTP session 19 */ 20 package connkilling 21 22 import ( 23 "context" 24 "strings" 25 "testing" 26 "time" 27 28 "github.com/stretchr/testify/require" 29 30 "vitess.io/vitess/go/vt/vttablet/endtoend/framework" 31 ) 32 33 func TestTxKillerKillsTransactionsInReservedConnections(t *testing.T) { 34 client := framework.NewClient() 35 defer client.Release() 36 37 _, err := client.ReserveBeginExecute("select 42", nil, nil, nil) 38 require.NoError(t, err) 39 40 assertIsKilledWithin(t, client, queryPollOpts{ 41 StopAfter: 6 * time.Second, 42 PollEvery: time.Second, 43 }) 44 } 45 46 func TestTxKillerDoesNotKillReservedConnectionsInUse(t *testing.T) { 47 client := framework.NewClient() 48 defer client.Release() 49 50 _, err := client.ReserveExecute("select 42", nil, nil) 51 require.NoError(t, err) 52 53 assertIsNotKilledOver5Second(t, client) 54 } 55 56 func TestTxKillerCountsTimeFromTxStartedNotStatefulConnCreated(t *testing.T) { 57 client := framework.NewClient() 58 defer client.Release() 59 60 // reserve connection at 0th second 61 _, err := client.ReserveExecute("select 42", nil, nil) 62 require.NoError(t, err) 63 64 // elapsed 2 seconds 65 time.Sleep(2 * time.Second) 66 67 // update the timer on tx start - new tx timer starts 68 _, err = client.BeginExecute("select 44", nil, nil) 69 require.NoError(t, err) 70 71 // elapsed 1 second from tx and 3 second from reserved conn. 72 time.Sleep(1 * time.Second) 73 _, err = client.Execute("select 43", nil) 74 require.NoError(t, err) 75 76 // elapsed 2 second from tx and 4 second from reserved conn. It does not fail. 77 time.Sleep(1 * time.Second) 78 _, err = client.Execute("select 43", nil) 79 require.NoError(t, err) 80 81 assertIsKilledWithin(t, client, queryPollOpts{ 82 StopAfter: 6 * time.Second, 83 PollEvery: time.Second, 84 }) 85 } 86 87 func TestTxKillerKillsTransactionThreeSecondsAfterCreation(t *testing.T) { 88 client := framework.NewClient() 89 defer client.Release() 90 91 _, err := client.BeginExecute("select 42", nil, nil) 92 require.NoError(t, err) 93 94 assertIsKilledWithin(t, client, queryPollOpts{ 95 StopAfter: 6 * time.Second, 96 PollEvery: time.Second, 97 }) 98 } 99 100 func assertIsNotKilledOver5Second(t *testing.T, client *framework.QueryClient) { 101 for i := 0; i < 5; i++ { 102 _, err := client.Execute("select 43", nil) 103 require.NoError(t, err) 104 time.Sleep(1 * time.Second) 105 } 106 } 107 108 type queryPollOpts struct { 109 StopAfter time.Duration 110 PollEvery time.Duration 111 } 112 113 func assertIsKilledWithin(t testing.TB, client *framework.QueryClient, opts queryPollOpts) { 114 t.Helper() 115 116 var err error 117 118 doQuery := func() { 119 _, err = client.Execute("select 43", nil) 120 if err != nil { 121 if strings.Contains(err.Error(), "in use: for tx killer rollback") { 122 t.Logf("tx is mid-rollback and not killed yet, ignoring this error: %s", err) 123 err = nil 124 } 125 } 126 } 127 128 ctx, cancel := context.WithTimeout(context.Background(), opts.StopAfter) 129 defer cancel() 130 131 defer func() { 132 // Check one last time after we've hit StopAfter 133 if err == nil { 134 doQuery() 135 } 136 137 // then it should still be killed. transactions are tracked per tx-creation time and not last-used time 138 require.Error(t, err) 139 require.Contains(t, err.Error(), "exceeded timeout: 3s") 140 }() 141 142 ticker := time.NewTicker(opts.PollEvery) 143 defer func() { 144 ticker.Stop() 145 select { 146 case <-ticker.C: 147 default: 148 } 149 }() 150 151 poll: 152 for { 153 select { 154 case <-ctx.Done(): 155 break poll 156 case <-ticker.C: 157 doQuery() 158 if err != nil { 159 break poll 160 } 161 } 162 } 163 }