vitess.io/vitess@v0.16.2/go/vt/throttler/manager_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 throttler 18 19 import ( 20 "fmt" 21 "reflect" 22 "sort" 23 "strings" 24 "testing" 25 "time" 26 27 "google.golang.org/protobuf/proto" 28 29 throttlerdatapb "vitess.io/vitess/go/vt/proto/throttlerdata" 30 ) 31 32 // We base our test data on these defaults. 33 var ( 34 defaultTargetLag = defaultMaxReplicationLagModuleConfig.TargetReplicationLagSec 35 defaultIgnoreNSlowestReplicas = defaultMaxReplicationLagModuleConfig.IgnoreNSlowestReplicas 36 ) 37 38 type managerTestFixture struct { 39 m *managerImpl 40 t1, t2 *Throttler 41 } 42 43 func (f *managerTestFixture) setUp() error { 44 f.m = newManager() 45 var err error 46 f.t1, err = newThrottler(f.m, "t1", "TPS", 1 /* threadCount */, MaxRateModuleDisabled, ReplicationLagModuleDisabled, time.Now) 47 if err != nil { 48 return err 49 } 50 f.t2, err = newThrottler(f.m, "t2", "TPS", 1 /* threadCount */, MaxRateModuleDisabled, ReplicationLagModuleDisabled, time.Now) 51 if err != nil { 52 return err 53 } 54 return nil 55 } 56 57 func (f *managerTestFixture) tearDown() { 58 f.t1.Close() 59 f.t2.Close() 60 } 61 62 func TestManager_Registration(t *testing.T) { 63 m := newManager() 64 t1, err := newThrottler(m, "t1", "TPS", 1 /* threadCount */, MaxRateModuleDisabled, ReplicationLagModuleDisabled, time.Now) 65 if err != nil { 66 t.Fatal(err) 67 } 68 if err := m.registerThrottler("t1", t1); err == nil { 69 t.Fatalf("manager should not accept a duplicate registration of a throttler: %v", err) 70 } 71 t1.Close() 72 73 // Unregistering an unregistered throttler should log an error. 74 m.unregisterThrottler("t1") 75 } 76 77 func TestManager_SetMaxRate(t *testing.T) { 78 f := &managerTestFixture{} 79 if err := f.setUp(); err != nil { 80 t.Fatal(err) 81 } 82 defer f.tearDown() 83 84 // Test SetMaxRate(). 85 want := []string{"t1", "t2"} 86 if got := f.m.SetMaxRate(23); !reflect.DeepEqual(got, want) { 87 t.Errorf("manager did not set the rate on all throttlers. got = %v, want = %v", got, want) 88 } 89 90 // Test MaxRates(). 91 wantRates := map[string]int64{ 92 "t1": 23, 93 "t2": 23, 94 } 95 if gotRates := f.m.MaxRates(); !reflect.DeepEqual(gotRates, wantRates) { 96 t.Errorf("manager did not set the rate on all throttlers. got = %v, want = %v", gotRates, wantRates) 97 } 98 } 99 100 func TestManager_GetConfiguration(t *testing.T) { 101 f := &managerTestFixture{} 102 if err := f.setUp(); err != nil { 103 t.Fatal(err) 104 } 105 defer f.tearDown() 106 107 // Test GetConfiguration() when all throttlers are returned. 108 want := map[string]*throttlerdatapb.Configuration{ 109 "t1": defaultMaxReplicationLagModuleConfig.Clone().Configuration, 110 "t2": defaultMaxReplicationLagModuleConfig.Clone().Configuration, 111 } 112 got, err := f.m.GetConfiguration("" /* all */) 113 if err != nil { 114 t.Fatal(err) 115 } 116 if !reflect.DeepEqual(got, want) { 117 t.Errorf("manager did not return the correct initial config for all throttlers. got = %v, want = %v", got, want) 118 } 119 120 // Test GetConfiguration() when a specific throttler is requested. 121 wantT2 := map[string]*throttlerdatapb.Configuration{ 122 "t2": defaultMaxReplicationLagModuleConfig.Clone().Configuration, 123 } 124 gotT2, err := f.m.GetConfiguration("t2") 125 if err != nil { 126 t.Fatal(err) 127 } 128 if !reflect.DeepEqual(gotT2, wantT2) { 129 t.Errorf("manager did not return the correct initial config for throttler: %v got = %v, want = %v", "t2", gotT2, wantT2) 130 } 131 132 // Now change the config and then reset it back. 133 newConfig := &throttlerdatapb.Configuration{ 134 TargetReplicationLagSec: defaultTargetLag + 1, 135 IgnoreNSlowestReplicas: defaultIgnoreNSlowestReplicas + 1, 136 } 137 allNames, err := f.m.UpdateConfiguration("", newConfig, false /* copyZeroValues */) 138 if err != nil { 139 t.Fatal(err) 140 } 141 // Verify it was changed. 142 if err := checkConfig(f.m, []string{"t1", "t2"}, allNames, defaultTargetLag+1, defaultIgnoreNSlowestReplicas+1); err != nil { 143 t.Fatal(err) 144 } 145 // Reset only "t2". 146 if names, err := f.m.ResetConfiguration("t2"); err != nil || !reflect.DeepEqual(names, []string{"t2"}) { 147 t.Fatalf("Reset failed or returned wrong throttler names: %v err: %v", names, err) 148 } 149 gotT2AfterReset, err := f.m.GetConfiguration("t2") 150 if err != nil { 151 t.Fatal(err) 152 } 153 if !reflect.DeepEqual(gotT2AfterReset, wantT2) { 154 t.Errorf("manager did not return the correct initial config for throttler %v after reset: got = %v, want = %v", "t2", gotT2AfterReset, wantT2) 155 } 156 // Reset all throttlers. 157 if names, err := f.m.ResetConfiguration(""); err != nil || !reflect.DeepEqual(names, []string{"t1", "t2"}) { 158 t.Fatalf("Reset failed or returned wrong throttler names: %v err: %v", names, err) 159 } 160 gotAfterReset, err := f.m.GetConfiguration("") 161 if err != nil { 162 t.Fatal(err) 163 } 164 if !reflect.DeepEqual(gotAfterReset, want) { 165 t.Errorf("manager did not return the correct initial config for all throttlers after reset. got = %v, want = %v", got, want) 166 } 167 } 168 169 func TestManager_UpdateConfiguration_Error(t *testing.T) { 170 f := &managerTestFixture{} 171 if err := f.setUp(); err != nil { 172 t.Fatal(err) 173 } 174 defer f.tearDown() 175 176 // Check that errors from Verify() are correctly propagated. 177 invalidConfig := &throttlerdatapb.Configuration{ 178 // max < 2 is not allowed. 179 MaxReplicationLagSec: 1, 180 } 181 if _, err := f.m.UpdateConfiguration("t2", invalidConfig, false /* copyZeroValues */); err == nil { 182 t.Fatal("expected error but got nil") 183 } else { 184 want := "max_replication_lag_sec must be >= 2" 185 if !strings.Contains(err.Error(), want) { 186 t.Fatalf("received wrong error. got = %v, want contains = %v", err, want) 187 } 188 } 189 } 190 191 func TestManager_UpdateConfiguration_Partial(t *testing.T) { 192 f := &managerTestFixture{} 193 if err := f.setUp(); err != nil { 194 t.Fatal(err) 195 } 196 defer f.tearDown() 197 198 // Verify that a partial update only updates that one field. 199 wantIgnoreNSlowestReplicas := defaultIgnoreNSlowestReplicas + 1 200 partialConfig := &throttlerdatapb.Configuration{ 201 IgnoreNSlowestReplicas: wantIgnoreNSlowestReplicas, 202 } 203 names, err := f.m.UpdateConfiguration("t2", partialConfig, false /* copyZeroValues */) 204 if err != nil { 205 t.Fatal(err) 206 } 207 if err := checkConfig(f.m, []string{"t2"}, names, defaultTargetLag, wantIgnoreNSlowestReplicas); err != nil { 208 t.Fatal(err) 209 } 210 // Repeat test for all throttlers. 211 allNames, err := f.m.UpdateConfiguration("" /* all */, partialConfig, false /* copyZeroValues */) 212 if err != nil { 213 t.Fatal(err) 214 } 215 if err := checkConfig(f.m, []string{"t1", "t2"}, allNames, defaultTargetLag, wantIgnoreNSlowestReplicas); err != nil { 216 t.Fatal(err) 217 } 218 } 219 220 func TestManager_UpdateConfiguration_ZeroValues(t *testing.T) { 221 f := &managerTestFixture{} 222 if err := f.setUp(); err != nil { 223 t.Fatal(err) 224 } 225 defer f.tearDown() 226 227 // Test the explicit copy of zero values. 228 zeroValueConfig := proto.Clone(defaultMaxReplicationLagModuleConfig.Configuration).(*throttlerdatapb.Configuration) 229 zeroValueConfig.IgnoreNSlowestReplicas = 0 230 names, err := f.m.UpdateConfiguration("t2", zeroValueConfig, true /* copyZeroValues */) 231 if err != nil { 232 t.Fatal(err) 233 } 234 if err := checkConfig(f.m, []string{"t2"}, names, defaultTargetLag, 0); err != nil { 235 t.Fatal(err) 236 } 237 // Repeat test for all throttlers. 238 allNames, err := f.m.UpdateConfiguration("" /* all */, zeroValueConfig, true /* copyZeroValues */) 239 if err != nil { 240 t.Fatal(err) 241 } 242 if err := checkConfig(f.m, []string{"t1", "t2"}, allNames, defaultTargetLag, 0); err != nil { 243 t.Fatal(err) 244 } 245 } 246 247 func checkConfig(m *managerImpl, throttlers []string, updatedThrottlers []string, targetLag int64, ignoreNSlowestReplicas int32) error { 248 // Sort list of throttler names because they came from a randomized Go map. 249 sort.Strings(updatedThrottlers) 250 251 if !reflect.DeepEqual(throttlers, updatedThrottlers) { 252 return fmt.Errorf("list of updated throttler names is wrong. got = %v, want = %v", throttlers, updatedThrottlers) 253 } 254 255 // Get configuration(s). 256 var throttlerName string 257 if len(throttlers) == 1 { 258 throttlerName = throttlers[0] 259 } 260 configs, err := m.GetConfiguration(throttlerName) 261 if err != nil { 262 return err 263 } 264 265 if throttlerName != "" { 266 if len(configs) != 1 { 267 return fmt.Errorf("GetConfiguration() should return only the configuration for throttler: %v but returned: %v", throttlerName, configs) 268 } 269 } 270 271 // Check each configuration. 272 for _, name := range throttlers { 273 if got, want := configs[name].IgnoreNSlowestReplicas, ignoreNSlowestReplicas; got != want { 274 return fmt.Errorf("%v: wrong throttler config for IgnoreNSlowestReplicas: got = %v, want = %v", name, got, want) 275 } 276 if got, want := configs[name].TargetReplicationLagSec, targetLag; got != want { 277 return fmt.Errorf("%v: wrong throttler config for TargetReplicationLagSec: got = %v, want = %v", name, got, want) 278 } 279 } 280 281 return nil 282 }