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  }