vitess.io/vitess@v0.16.2/go/vt/throttler/throttlerclienttest/throttlerclient_testsuite.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 throttlerclienttest contains the testsuite against which each 18 // RPC implementation of the throttlerclient interface must be tested. 19 package throttlerclienttest 20 21 // NOTE: This file is not test-only code because it is referenced by 22 // tests in other packages and therefore it has to be regularly 23 // visible. 24 25 // NOTE: This code is in its own package such that its dependencies 26 // (e.g. zookeeper) won't be drawn into production binaries as well. 27 28 import ( 29 "reflect" 30 "strings" 31 "testing" 32 33 "context" 34 35 "google.golang.org/protobuf/proto" 36 37 "vitess.io/vitess/go/vt/throttler" 38 "vitess.io/vitess/go/vt/throttler/throttlerclient" 39 40 throttlerdatapb "vitess.io/vitess/go/vt/proto/throttlerdata" 41 ) 42 43 // TestSuite runs the test suite on the given throttlerclient and throttlerserver. 44 func TestSuite(t *testing.T, c throttlerclient.Client) { 45 tf := &testFixture{} 46 if err := tf.setUp(); err != nil { 47 t.Fatal(err) 48 } 49 defer tf.tearDown() 50 51 tf.maxRates(t, c) 52 53 tf.setMaxRate(t, c) 54 55 tf.configuration(t, c) 56 } 57 58 // TestSuitePanics tests the panic handling of each RPC method. Unlike TestSuite 59 // it does not use the real throttler.managerImpl. Instead, it uses FakeManager 60 // which allows us to panic on each RPC. 61 func TestSuitePanics(t *testing.T, c throttlerclient.Client) { 62 maxRatesPanics(t, c) 63 64 setMaxRatePanics(t, c) 65 66 getConfigurationPanics(t, c) 67 68 updateConfigurationPanics(t, c) 69 70 resetConfigurationPanics(t, c) 71 } 72 73 var throttlerNames = []string{"t1", "t2"} 74 75 type testFixture struct { 76 throttlers []*throttler.Throttler 77 } 78 79 func (tf *testFixture) setUp() error { 80 for _, name := range throttlerNames { 81 t, err := throttler.NewThrottler(name, "TPS", 1 /* threadCount */, 1, throttler.ReplicationLagModuleDisabled) 82 if err != nil { 83 return err 84 } 85 tf.throttlers = append(tf.throttlers, t) 86 } 87 return nil 88 } 89 90 func (tf *testFixture) tearDown() { 91 for _, t := range tf.throttlers { 92 t.Close() 93 } 94 } 95 96 func (tf *testFixture) maxRates(t *testing.T, client throttlerclient.Client) { 97 _, err := client.SetMaxRate(context.Background(), 23) 98 if err != nil { 99 t.Fatalf("Cannot execute remote command: %v", err) 100 } 101 102 got, err := client.MaxRates(context.Background()) 103 if err != nil { 104 t.Fatalf("Cannot execute remote command: %v", err) 105 } 106 want := map[string]int64{ 107 "t1": 23, 108 "t2": 23, 109 } 110 if !reflect.DeepEqual(got, want) { 111 t.Fatalf("rate was not updated on all registered throttlers. got = %v, want = %v", got, throttlerNames) 112 } 113 } 114 115 func (tf *testFixture) setMaxRate(t *testing.T, client throttlerclient.Client) { 116 got, err := client.SetMaxRate(context.Background(), 23) 117 if err != nil { 118 t.Fatalf("Cannot execute remote command: %v", err) 119 } 120 121 if !reflect.DeepEqual(got, throttlerNames) { 122 t.Fatalf("rate was not updated on all registered throttlers. got = %v, want = %v", got, throttlerNames) 123 } 124 } 125 126 func (tf *testFixture) configuration(t *testing.T, client throttlerclient.Client) { 127 initialConfigs, err := client.GetConfiguration(context.Background(), "" /* all */) 128 if err != nil { 129 t.Fatalf("Cannot execute remote command: %v", err) 130 } 131 132 // Test UpdateConfiguration. 133 config := &throttlerdatapb.Configuration{ 134 TargetReplicationLagSec: 1, 135 MaxReplicationLagSec: 2, 136 InitialRate: 3, 137 MaxIncrease: 0.4, 138 EmergencyDecrease: 0.5, 139 MinDurationBetweenIncreasesSec: 6, 140 MaxDurationBetweenIncreasesSec: 7, 141 MinDurationBetweenDecreasesSec: 8, 142 SpreadBacklogAcrossSec: 9, 143 IgnoreNSlowestReplicas: 10, 144 IgnoreNSlowestRdonlys: 11, 145 AgeBadRateAfterSec: 12, 146 BadRateIncrease: 0.13, 147 MaxRateApproachThreshold: 0.9, 148 } 149 names, err := client.UpdateConfiguration(context.Background(), "t2", config /* false */, true /* copyZeroValues */) 150 if err != nil { 151 t.Fatalf("Cannot execute remote command: %v", err) 152 } 153 if got, want := names, []string{"t2"}; !reflect.DeepEqual(got, want) { 154 t.Fatalf("returned names of updated throttlers is wrong. got = %v, want = %v", got, want) 155 } 156 157 // Test GetConfiguration. 158 configs, err := client.GetConfiguration(context.Background(), "t2") 159 if err != nil { 160 t.Fatalf("Cannot execute remote command: %v", err) 161 } 162 if len(configs) != 1 || configs["t2"] == nil { 163 t.Fatalf("wrong named configuration returned. got = %v, want configuration for t2", configs) 164 } 165 if got, want := configs["t2"], config; !proto.Equal(got, want) { 166 t.Fatalf("did not read updated config. got = %v, want = %v", got, want) 167 } 168 169 // Reset should return the initial configs. 170 namesForReset, err := client.ResetConfiguration(context.Background(), "" /* all */) 171 if err != nil { 172 t.Fatalf("Cannot execute remote command: %v", err) 173 } 174 if got, want := namesForReset, throttlerNames; !reflect.DeepEqual(got, want) { 175 t.Fatalf("returned names of reset throttlers is wrong. got = %v, want = %v", got, want) 176 } 177 178 // Verify that it was correctly set. 179 configsAfterReset, err := client.GetConfiguration(context.Background(), "" /* all */) 180 if err != nil { 181 t.Fatalf("Cannot execute remote command: %v", err) 182 } 183 if got, want := configsAfterReset, initialConfigs; !reflect.DeepEqual(got, want) { 184 t.Fatalf("wrong configurations after reset. got = %v, want = %v", got, want) 185 } 186 } 187 188 // FakeManager implements the throttler.Manager interface and panics on all 189 // methods defined in the interface. 190 type FakeManager struct { 191 } 192 193 const panicMsg = "RPC server implementation should handle this" 194 195 // MaxRates implements the throttler.Manager interface. It always panics. 196 func (fm *FakeManager) MaxRates() map[string]int64 { 197 panic(panicMsg) 198 } 199 200 // SetMaxRate implements the throttler.Manager interface. It always panics. 201 func (fm *FakeManager) SetMaxRate(int64) []string { 202 panic(panicMsg) 203 } 204 205 // GetConfiguration implements the throttler.Manager interface. It always panics. 206 func (fm *FakeManager) GetConfiguration(throttlerName string) (map[string]*throttlerdatapb.Configuration, error) { 207 panic(panicMsg) 208 } 209 210 // UpdateConfiguration implements the throttler.Manager interface. It always panics. 211 func (fm *FakeManager) UpdateConfiguration(throttlerName string, configuration *throttlerdatapb.Configuration, copyZeroValues bool) ([]string, error) { 212 panic(panicMsg) 213 } 214 215 // ResetConfiguration implements the throttler.Manager interface. It always panics. 216 func (fm *FakeManager) ResetConfiguration(throttlerName string) ([]string, error) { 217 panic(panicMsg) 218 } 219 220 // Test methods which test for each RPC that panics are caught. 221 222 func maxRatesPanics(t *testing.T, client throttlerclient.Client) { 223 _, err := client.MaxRates(context.Background()) 224 if !errorFromPanicHandler(err) { 225 t.Fatalf("MaxRates RPC implementation does not catch panics properly: %v", err) 226 } 227 } 228 229 func setMaxRatePanics(t *testing.T, client throttlerclient.Client) { 230 _, err := client.SetMaxRate(context.Background(), 23) 231 if !errorFromPanicHandler(err) { 232 t.Fatalf("SetMaxRate RPC implementation does not catch panics properly: %v", err) 233 } 234 } 235 236 func getConfigurationPanics(t *testing.T, client throttlerclient.Client) { 237 _, err := client.GetConfiguration(context.Background(), "") 238 if !errorFromPanicHandler(err) { 239 t.Fatalf("GetConfiguration RPC implementation does not catch panics properly: %v", err) 240 } 241 } 242 243 func updateConfigurationPanics(t *testing.T, client throttlerclient.Client) { 244 _, err := client.UpdateConfiguration(context.Background(), "", nil, false) 245 if !errorFromPanicHandler(err) { 246 t.Fatalf("UpdateConfiguration RPC implementation does not catch panics properly: %v", err) 247 } 248 } 249 250 func resetConfigurationPanics(t *testing.T, client throttlerclient.Client) { 251 _, err := client.ResetConfiguration(context.Background(), "") 252 if !errorFromPanicHandler(err) { 253 t.Fatalf("ResetConfiguration RPC implementation does not catch panics properly: %v", err) 254 } 255 } 256 257 func errorFromPanicHandler(err error) bool { 258 if err == nil || !strings.Contains(err.Error(), panicMsg) { 259 return false 260 } 261 return true 262 }