vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/txlimiter/tx_limiter_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 txlimiter 18 19 import ( 20 "testing" 21 22 "vitess.io/vitess/go/vt/callerid" 23 "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" 24 25 querypb "vitess.io/vitess/go/vt/proto/query" 26 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 27 ) 28 29 func resetVariables(txl *Impl) { 30 txl.rejections.ResetAll() 31 txl.rejectionsDryRun.ResetAll() 32 } 33 34 func createCallers(username, principal, component, subcomponent string) (*querypb.VTGateCallerID, *vtrpcpb.CallerID) { 35 im := callerid.NewImmediateCallerID(username) 36 ef := callerid.NewEffectiveCallerID(principal, component, subcomponent) 37 return im, ef 38 } 39 40 func TestTxLimiter_DisabledAllowsAll(t *testing.T) { 41 config := tabletenv.NewDefaultConfig() 42 config.TxPool.Size = 10 43 config.TransactionLimitPerUser = 0.1 44 config.EnableTransactionLimit = false 45 config.EnableTransactionLimitDryRun = false 46 config.TransactionLimitByUsername = false 47 config.TransactionLimitByPrincipal = false 48 config.TransactionLimitByComponent = false 49 config.TransactionLimitBySubcomponent = false 50 limiter := New(tabletenv.NewEnv(config, "TabletServerTest")) 51 im, ef := createCallers("", "", "", "") 52 for i := 0; i < 5; i++ { 53 if got, want := limiter.Get(im, ef), true; got != want { 54 t.Errorf("Transaction number %d, Get(): got %v, want %v", i, got, want) 55 } 56 } 57 58 } 59 60 func TestTxLimiter_LimitsOnlyOffendingUser(t *testing.T) { 61 config := tabletenv.NewDefaultConfig() 62 config.TxPool.Size = 10 63 config.TransactionLimitPerUser = 0.3 64 config.EnableTransactionLimit = true 65 config.EnableTransactionLimitDryRun = false 66 config.TransactionLimitByUsername = true 67 config.TransactionLimitByPrincipal = false 68 config.TransactionLimitByComponent = false 69 config.TransactionLimitBySubcomponent = false 70 71 // This should allow 3 slots to all users 72 newlimiter := New(tabletenv.NewEnv(config, "TabletServerTest")) 73 limiter, ok := newlimiter.(*Impl) 74 if !ok { 75 t.Fatalf("New returned limiter of unexpected type: got %T, want %T", newlimiter, limiter) 76 } 77 resetVariables(limiter) 78 im1, ef1 := createCallers("user1", "", "", "") 79 im2, ef2 := createCallers("user2", "", "", "") 80 81 // user1 uses 3 slots 82 for i := 0; i < 3; i++ { 83 if got, want := limiter.Get(im1, ef1), true; got != want { 84 t.Errorf("Transaction number %d, Get(im1, ef1): got %v, want %v", i, got, want) 85 } 86 } 87 88 // user1 not allowed to use 4th slot, which increases counter 89 if got, want := limiter.Get(im1, ef1), false; got != want { 90 t.Errorf("Get(im1, ef1) after using up all allowed attempts: got %v, want %v", got, want) 91 } 92 93 key1 := limiter.extractKey(im1, ef1) 94 if got, want := limiter.rejections.Counts()[key1], int64(1); got != want { 95 t.Errorf("Rejections count for %s: got %d, want %d", key1, got, want) 96 } 97 98 // user2 uses 3 slots 99 for i := 0; i < 3; i++ { 100 if got, want := limiter.Get(im2, ef2), true; got != want { 101 t.Errorf("Transaction number %d, Get(im2, ef2): got %v, want %v", i, got, want) 102 } 103 } 104 105 // user2 not allowed to use 4th slot, which increases counter 106 if got, want := limiter.Get(im2, ef2), false; got != want { 107 t.Errorf("Get(im2, ef2) after using up all allowed attempts: got %v, want %v", got, want) 108 } 109 key2 := limiter.extractKey(im2, ef2) 110 if got, want := limiter.rejections.Counts()[key2], int64(1); got != want { 111 t.Errorf("Rejections count for %s: got %d, want %d", key2, got, want) 112 } 113 114 // user1 releases a slot, which allows to get another 115 limiter.Release(im1, ef1) 116 if got, want := limiter.Get(im1, ef1), true; got != want { 117 t.Errorf("Get(im1, ef1) after releasing: got %v, want %v", got, want) 118 } 119 120 // Rejection coutner for user 1 should still be 1. 121 if got, want := limiter.rejections.Counts()[key1], int64(1); got != want { 122 t.Errorf("Rejections count for %s: got %d, want %d", key1, got, want) 123 } 124 } 125 126 func TestTxLimiterDryRun(t *testing.T) { 127 config := tabletenv.NewDefaultConfig() 128 config.TxPool.Size = 10 129 config.TransactionLimitPerUser = 0.3 130 config.EnableTransactionLimit = true 131 config.EnableTransactionLimitDryRun = true 132 config.TransactionLimitByUsername = true 133 config.TransactionLimitByPrincipal = false 134 config.TransactionLimitByComponent = false 135 config.TransactionLimitBySubcomponent = false 136 137 // This should allow 3 slots to all users 138 newlimiter := New(tabletenv.NewEnv(config, "TabletServerTest")) 139 limiter, ok := newlimiter.(*Impl) 140 if !ok { 141 t.Fatalf("New returned limiter of unexpected type: got %T, want %T", newlimiter, limiter) 142 } 143 resetVariables(limiter) 144 im, ef := createCallers("user", "", "", "") 145 key := limiter.extractKey(im, ef) 146 147 // uses 3 slots 148 for i := 0; i < 3; i++ { 149 if got, want := limiter.Get(im, ef), true; got != want { 150 t.Errorf("Transaction number %d, Get(im, ef): got %v, want %v", i, got, want) 151 } 152 } 153 154 // allowed to use 4th slot, but dry run rejection counter increased 155 if got, want := limiter.Get(im, ef), true; got != want { 156 t.Errorf("Get(im, ef) after using up all allowed attempts: got %v, want %v", got, want) 157 } 158 159 if got, want := limiter.rejections.Counts()[key], int64(0); got != want { 160 t.Errorf("Rejections count for %s: got %d, want %d", key, got, want) 161 } 162 if got, want := limiter.rejectionsDryRun.Counts()[key], int64(1); got != want { 163 t.Errorf("RejectionsDryRun count for %s: got %d, want %d", key, got, want) 164 } 165 }