vitess.io/vitess@v0.16.2/go/vt/vttablet/tabletserver/rules/map_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 rules
    18  
    19  import (
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	"vitess.io/vitess/go/vt/vttablet/tabletserver/planbuilder"
    25  )
    26  
    27  var (
    28  	denyRules  *Rules
    29  	otherRules *Rules
    30  )
    31  
    32  const (
    33  	// mimic query rules from denylist
    34  	denyListQueryRules string = "DENYLIST_QUERY_RULES"
    35  	// mimic query rules from custom source
    36  	customQueryRules string = "CUSTOM_QUERY_RULES"
    37  )
    38  
    39  func setupRules() {
    40  	var qr *Rule
    41  
    42  	// mock denied tables
    43  	denyRules = New()
    44  	deniedTables := []string{"bannedtable1", "bannedtable2", "bannedtable3"}
    45  	qr = NewQueryRule("enforce denied tables", "denied_table", QRFailRetry)
    46  	for _, t := range deniedTables {
    47  		qr.AddTableCond(t)
    48  	}
    49  	denyRules.Add(qr)
    50  
    51  	// mock custom rules
    52  	otherRules = New()
    53  	qr = NewQueryRule("sample custom rule", "customrule_ban_bindvar", QRFail)
    54  	qr.AddTableCond("t_customer")
    55  	qr.AddBindVarCond("bindvar1", true, false, QRNoOp, nil)
    56  	otherRules.Add(qr)
    57  }
    58  
    59  func TestMapRegisterARegisteredSource(t *testing.T) {
    60  	setupRules()
    61  	qri := NewMap()
    62  	qri.RegisterSource(denyListQueryRules)
    63  	defer func() {
    64  		err := recover()
    65  		if err == nil {
    66  			t.Fatalf("should get an error for registering a registered query rule source ")
    67  		}
    68  	}()
    69  	qri.RegisterSource(denyListQueryRules)
    70  }
    71  
    72  func TestMapSetRulesWithNil(t *testing.T) {
    73  	setupRules()
    74  	qri := NewMap()
    75  
    76  	qri.RegisterSource(denyListQueryRules)
    77  	err := qri.SetRules(denyListQueryRules, denyRules)
    78  	if err != nil {
    79  		t.Errorf("Failed to set denyListQueryRules Rules : %s", err)
    80  	}
    81  	qrs, err := qri.Get(denyListQueryRules)
    82  	if err != nil {
    83  		t.Errorf("GetRules failed to retrieve denyListQueryRules that has been set: %s", err)
    84  	}
    85  	if !reflect.DeepEqual(qrs, denyRules) {
    86  		t.Errorf("denyListQueryRules retrieved is %v, but the expected value should be %v", qrs, denyListQueryRules)
    87  	}
    88  
    89  	qri.SetRules(denyListQueryRules, nil)
    90  
    91  	qrs, err = qri.Get(denyListQueryRules)
    92  	if err != nil {
    93  		t.Errorf("GetRules failed to retrieve denyListQueryRules that has been set: %s", err)
    94  	}
    95  	if !reflect.DeepEqual(qrs, New()) {
    96  		t.Errorf("denyListQueryRules retrieved is %v, but the expected value should be %v", qrs, denyListQueryRules)
    97  	}
    98  }
    99  
   100  func TestMapGetSetQueryRules(t *testing.T) {
   101  	setupRules()
   102  	qri := NewMap()
   103  
   104  	qri.RegisterSource(denyListQueryRules)
   105  	qri.RegisterSource(customQueryRules)
   106  
   107  	// Test if we can get a Rules without a predefined rule set name
   108  	qrs, err := qri.Get("Foo")
   109  	if err == nil {
   110  		t.Errorf("GetRules shouldn't succeed with 'Foo' as the rule set name")
   111  	}
   112  	if qrs == nil {
   113  		t.Errorf("GetRules should always return empty Rules and never nil")
   114  	}
   115  	if !reflect.DeepEqual(qrs, New()) {
   116  		t.Errorf("Map contains only empty Rules at the beginning")
   117  	}
   118  
   119  	// Test if we can set a Rules without a predefined rule set name
   120  	err = qri.SetRules("Foo", New())
   121  	if err == nil {
   122  		t.Errorf("SetRules shouldn't succeed with 'Foo' as the rule set name")
   123  	}
   124  
   125  	// Test if we can successfully set Rules previously mocked into Map
   126  	err = qri.SetRules(denyListQueryRules, denyRules)
   127  	if err != nil {
   128  		t.Errorf("Failed to set denylist Rules : %s", err)
   129  	}
   130  	err = qri.SetRules(denyListQueryRules, denyRules)
   131  	if err != nil {
   132  		t.Errorf("Failed to set denylist Rules: %s", err)
   133  	}
   134  	err = qri.SetRules(customQueryRules, otherRules)
   135  	if err != nil {
   136  		t.Errorf("Failed to set custom Rules: %s", err)
   137  	}
   138  
   139  	// Test if we can successfully retrieve rules that've been set
   140  	qrs, err = qri.Get(denyListQueryRules)
   141  	if err != nil {
   142  		t.Errorf("GetRules failed to retrieve denyListQueryRules that has been set: %s", err)
   143  	}
   144  	if !reflect.DeepEqual(qrs, denyRules) {
   145  		t.Errorf("denyListQueryRules retrieved is %v, but the expected value should be %v", qrs, denyRules)
   146  	}
   147  
   148  	qrs, err = qri.Get(denyListQueryRules)
   149  	if err != nil {
   150  		t.Errorf("GetRules failed to retrieve denyListQueryRules that has been set: %s", err)
   151  	}
   152  	if !reflect.DeepEqual(qrs, denyRules) {
   153  		t.Errorf("denyListQueryRules retrieved is %v, but the expected value should be %v", qrs, denyRules)
   154  	}
   155  
   156  	qrs, err = qri.Get(customQueryRules)
   157  	if err != nil {
   158  		t.Errorf("GetRules failed to retrieve customQueryRules that has been set: %s", err)
   159  	}
   160  	if !reflect.DeepEqual(qrs, otherRules) {
   161  		t.Errorf("customQueryRules retrieved is %v, but the expected value should be %v", qrs, customQueryRules)
   162  	}
   163  }
   164  
   165  func TestMapFilterByPlan(t *testing.T) {
   166  	var qrs *Rules
   167  	setupRules()
   168  	qri := NewMap()
   169  
   170  	qri.RegisterSource(denyListQueryRules)
   171  	qri.RegisterSource(customQueryRules)
   172  
   173  	qri.SetRules(denyListQueryRules, denyRules)
   174  	qri.SetRules(customQueryRules, otherRules)
   175  
   176  	// Test filter by denylist rule
   177  	qrs = qri.FilterByPlan("select * from bannedtable2", planbuilder.PlanSelect, "bannedtable2")
   178  	if l := len(qrs.rules); l != 1 {
   179  		t.Errorf("Select from bannedtable matches %d rules, but we expect %d", l, 1)
   180  	}
   181  	if !strings.HasPrefix(qrs.rules[0].Name, "denied_table") {
   182  		t.Errorf("Select from bannedtable query matches rule '%s', but we expect rule with prefix '%s'", qrs.rules[0].Name, "denied_table")
   183  	}
   184  
   185  	// Test filter by custom rule
   186  	qrs = qri.FilterByPlan("select cid from t_customer limit 10", planbuilder.PlanSelect, "t_customer")
   187  	if l := len(qrs.rules); l != 1 {
   188  		t.Errorf("Select from t_customer matches %d rules, but we expect %d", l, 1)
   189  	}
   190  	if !strings.HasPrefix(qrs.rules[0].Name, "customrule_ban_bindvar") {
   191  		t.Errorf("Select from t_customer matches rule '%s', but we expect rule with prefix '%s'", qrs.rules[0].Name, "customrule_ban_bindvar")
   192  	}
   193  
   194  	// Test match two rules: both denylist rule and custom rule will be matched
   195  	otherRules = New()
   196  	qr := NewQueryRule("sample custom rule", "customrule_ban_bindvar", QRFail)
   197  	qr.AddBindVarCond("bindvar1", true, false, QRNoOp, nil)
   198  	otherRules.Add(qr)
   199  	qri.SetRules(customQueryRules, otherRules)
   200  	qrs = qri.FilterByPlan("select * from bannedtable2", planbuilder.PlanSelect, "bannedtable2")
   201  	if l := len(qrs.rules); l != 2 {
   202  		t.Errorf("Insert into bannedtable2 matches %d rules: %v, but we expect %d rules to be matched", l, qrs.rules, 2)
   203  	}
   204  }
   205  
   206  func TestMapJSON(t *testing.T) {
   207  	setupRules()
   208  	qri := NewMap()
   209  	qri.RegisterSource(denyListQueryRules)
   210  	_ = qri.SetRules(denyListQueryRules, denyRules)
   211  	qri.RegisterSource(customQueryRules)
   212  	_ = qri.SetRules(customQueryRules, otherRules)
   213  	got := marshalled(qri)
   214  	want := compacted(`{
   215  		"CUSTOM_QUERY_RULES":[{
   216  			"Description":"sample custom rule",
   217  			"Name":"customrule_ban_bindvar",
   218  			"TableNames":["t_customer"],
   219  			"BindVarConds":[{"Name":"bindvar1","OnAbsent":true,"Operator":""}],
   220  			"Action":"FAIL"
   221  		}],
   222  		"DENYLIST_QUERY_RULES":[{
   223  			"Description":"enforce denied tables",
   224  			"Name":"denied_table",
   225  			"TableNames":["bannedtable1","bannedtable2","bannedtable3"],
   226  			"Action":"FAIL_RETRY"
   227  		}]
   228  	}`)
   229  	if got != want {
   230  		t.Errorf("MapJSON:\n%v, want\n%v", got, want)
   231  	}
   232  }