github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/mw_organization_activity_test.go (about) 1 // +build !race 2 3 package gateway 4 5 import ( 6 "net/http" 7 "testing" 8 "time" 9 10 uuid "github.com/satori/go.uuid" 11 12 "github.com/TykTechnologies/tyk/config" 13 "github.com/TykTechnologies/tyk/test" 14 ) 15 16 func testPrepareProcessRequestQuotaLimit(tb testing.TB, ts *Test, data map[string]interface{}) { 17 // load API 18 orgID := "test-org-" + uuid.NewV4().String() 19 BuildAndLoadAPI(func(spec *APISpec) { 20 spec.UseKeylessAccess = true 21 spec.OrgID = orgID 22 spec.Proxy.ListenPath = "/" 23 }) 24 25 data["org_id"] = orgID 26 27 // create org key with quota 28 ts.Run(tb, test.TestCase{ 29 Path: "/tyk/org/keys/" + orgID + "?reset_quota=1", 30 AdminAuth: true, 31 Method: http.MethodPost, 32 Code: http.StatusOK, 33 Data: data, 34 }) 35 } 36 37 func TestProcessRequestLiveQuotaLimit(t *testing.T) { 38 // setup global config 39 globalConf := config.Global() 40 globalConf.EnforceOrgQuotas = true 41 globalConf.ExperimentalProcessOrgOffThread = false 42 config.SetGlobal(globalConf) 43 44 // run test server 45 ts := StartTest() 46 defer ts.Close() 47 48 // load API 49 testPrepareProcessRequestQuotaLimit( 50 t, 51 ts, 52 map[string]interface{}{ 53 "quota_max": 10, 54 "quota_remaining": 10, 55 "quota_renewal_rate": 3, 56 }, 57 ) 58 59 t.Run("Process request live with quota", func(t *testing.T) { 60 // 1st ten requests within quota 61 for i := 0; i < 10; i++ { 62 ts.Run(t, test.TestCase{ 63 Code: http.StatusOK, 64 }) 65 } 66 67 // next request should fail with 403 as it is out of quota 68 ts.Run(t, test.TestCase{ 69 Code: http.StatusForbidden, 70 }) 71 72 // wait for renewal 73 time.Sleep(4 * time.Second) 74 75 // next one should be OK 76 ts.Run(t, test.TestCase{ 77 Code: http.StatusOK, 78 }) 79 }) 80 } 81 82 func BenchmarkProcessRequestLiveQuotaLimit(b *testing.B) { 83 b.ReportAllocs() 84 85 // setup global config 86 globalConf := config.Global() 87 globalConf.EnforceOrgQuotas = true 88 globalConf.ExperimentalProcessOrgOffThread = false 89 config.SetGlobal(globalConf) 90 91 defer ResetTestConfig() 92 93 // run test server 94 ts := StartTest() 95 defer ts.Close() 96 97 // load API 98 testPrepareProcessRequestQuotaLimit( 99 b, 100 ts, 101 map[string]interface{}{ 102 "quota_max": 100000000, 103 "quota_remaining": 100000000, 104 "quota_renewal_rate": 300, 105 }, 106 ) 107 108 for i := 0; i < b.N; i++ { 109 ts.Run(b, test.TestCase{ 110 Code: http.StatusOK, 111 }) 112 } 113 } 114 115 func TestProcessRequestOffThreadQuotaLimit(t *testing.T) { 116 // run test server 117 ts := StartTest() 118 defer ts.Close() 119 120 // setup global config 121 globalConf := config.Global() 122 globalConf.EnforceOrgQuotas = true 123 globalConf.ExperimentalProcessOrgOffThread = true 124 config.SetGlobal(globalConf) 125 defer ResetTestConfig() 126 127 // load API 128 testPrepareProcessRequestQuotaLimit( 129 t, 130 ts, 131 map[string]interface{}{ 132 "quota_max": 10, 133 "quota_remaining": 10, 134 "quota_renewal_rate": 2, 135 }, 136 ) 137 138 t.Run("Process request off thread with quota", func(t *testing.T) { 139 // at least first 10 requests within quota should be OK 140 for i := 0; i < 10; i++ { 141 ts.Run(t, test.TestCase{ 142 Code: http.StatusOK, 143 }) 144 } 145 146 // some of next request should fail with 403 as it is out of quota 147 failed := false 148 i := 0 149 for i = 0; i < 11; i++ { 150 res, _ := ts.Run(t, test.TestCase{}) 151 res.Body.Close() 152 if res.StatusCode == http.StatusForbidden { 153 failed = true 154 break 155 } 156 } 157 if !failed { 158 t.Error("Requests don't fail after quota exceeded") 159 } else { 160 t.Logf("Failed with 403 after %d requests over quota", i) 161 } 162 163 // wait for renewal 164 time.Sleep(4 * time.Second) 165 166 // next 10 requests should be OK again 167 ok := false 168 for i = 0; i < 9; i++ { 169 res, _ := ts.Run(t, test.TestCase{Delay: 10 * time.Millisecond}) 170 res.Body.Close() 171 if res.StatusCode == http.StatusOK { 172 ok = true 173 break 174 } 175 } 176 if !ok { 177 t.Error("Requests still failing after quota renewal") 178 } else { 179 t.Logf("Started responding with 200 after %d requests after quota renewal", i) 180 } 181 }) 182 } 183 184 func BenchmarkProcessRequestOffThreadQuotaLimit(b *testing.B) { 185 b.ReportAllocs() 186 187 // setup global config 188 globalConf := config.Global() 189 globalConf.EnforceOrgQuotas = true 190 globalConf.ExperimentalProcessOrgOffThread = true 191 config.SetGlobal(globalConf) 192 193 defer ResetTestConfig() 194 195 // run test server 196 ts := StartTest() 197 defer ts.Close() 198 199 // load API 200 testPrepareProcessRequestQuotaLimit( 201 b, 202 ts, 203 map[string]interface{}{ 204 "quota_max": 100000000, 205 "quota_remaining": 100000000, 206 "quota_renewal_rate": 300, 207 }, 208 ) 209 210 for i := 0; i < b.N; i++ { 211 ts.Run(b, test.TestCase{ 212 Code: http.StatusOK, 213 }) 214 } 215 } 216 217 func TestProcessRequestLiveRedisRollingLimiter(t *testing.T) { 218 // setup global config 219 globalConf := config.Global() 220 globalConf.EnforceOrgQuotas = true 221 globalConf.EnableRedisRollingLimiter = true 222 globalConf.ExperimentalProcessOrgOffThread = false 223 config.SetGlobal(globalConf) 224 defer ResetTestConfig() 225 226 // run test server 227 ts := StartTest() 228 defer ts.Close() 229 230 // load API 231 testPrepareProcessRequestQuotaLimit( 232 t, 233 ts, 234 map[string]interface{}{ 235 "quota_max": -1, 236 "rate": 10, 237 "per": 1, 238 }, 239 ) 240 241 t.Run("Process request live with rate limit", func(t *testing.T) { 242 // ten requests per sec should be OK 243 for i := 0; i < 10; i++ { 244 ts.Run(t, test.TestCase{ 245 Code: http.StatusOK, 246 }) 247 } 248 249 // wait for next time window 250 time.Sleep(2 * time.Second) 251 252 // try to run over rate limit 253 reqNum := 1 254 for { 255 resp, _ := ts.Run(t, test.TestCase{}) 256 resp.Body.Close() 257 if resp.StatusCode == http.StatusForbidden { 258 break 259 } 260 reqNum++ 261 } 262 263 if reqNum < 10 { 264 t.Errorf("Started failing too early after %d requests", reqNum) 265 } else { 266 t.Logf("Started failing after %d requests over limit", reqNum-10) 267 } 268 }) 269 } 270 271 func BenchmarkProcessRequestLiveRedisRollingLimiter(b *testing.B) { 272 b.ReportAllocs() 273 274 // setup global config 275 globalConf := config.Global() 276 globalConf.EnforceOrgQuotas = true 277 globalConf.EnableRedisRollingLimiter = true 278 globalConf.ExperimentalProcessOrgOffThread = false 279 config.SetGlobal(globalConf) 280 281 defer ResetTestConfig() 282 283 // run test server 284 ts := StartTest() 285 defer ts.Close() 286 287 // load API 288 testPrepareProcessRequestQuotaLimit( 289 b, 290 ts, 291 map[string]interface{}{ 292 "quota_max": -1, 293 "rate": 10000, 294 "per": 1, 295 }, 296 ) 297 298 for i := 0; i < b.N; i++ { 299 ts.Run(b, test.TestCase{ 300 Code: http.StatusOK, 301 }) 302 } 303 } 304 305 func TestProcessRequestOffThreadRedisRollingLimiter(t *testing.T) { 306 // setup global config 307 globalConf := config.Global() 308 globalConf.EnforceOrgQuotas = true 309 globalConf.EnableRedisRollingLimiter = true 310 globalConf.ExperimentalProcessOrgOffThread = true 311 config.SetGlobal(globalConf) 312 defer ResetTestConfig() 313 314 // run test server 315 ts := StartTest() 316 defer ts.Close() 317 318 // load API 319 testPrepareProcessRequestQuotaLimit( 320 t, 321 ts, 322 map[string]interface{}{ 323 "quota_max": -1, 324 "rate": 10, 325 "per": 1, 326 }, 327 ) 328 329 t.Run("Process request off thread with rate limit", func(t *testing.T) { 330 // ten requests per sec should be OK 331 for i := 0; i < 10; i++ { 332 ts.Run(t, test.TestCase{ 333 Code: http.StatusOK, 334 }) 335 } 336 337 // wait for next time window 338 time.Sleep(2 * time.Second) 339 340 // try to run over rate limit 341 reqNum := 1 342 for { 343 resp, _ := ts.Run(t, test.TestCase{}) 344 resp.Body.Close() 345 if resp.StatusCode == http.StatusForbidden { 346 break 347 } 348 reqNum++ 349 } 350 351 if reqNum < 10 { 352 t.Errorf("Started failing too early after %d requests", reqNum) 353 } else { 354 t.Logf("Started failing after %d requests over limit", reqNum-10) 355 } 356 }) 357 } 358 359 func BenchmarkProcessRequestOffThreadRedisRollingLimiter(b *testing.B) { 360 b.ReportAllocs() 361 362 // setup global config 363 globalConf := config.Global() 364 globalConf.EnforceOrgQuotas = true 365 globalConf.EnableRedisRollingLimiter = true 366 globalConf.ExperimentalProcessOrgOffThread = true 367 config.SetGlobal(globalConf) 368 369 // run test server 370 ts := StartTest() 371 defer ts.Close() 372 373 // load API 374 testPrepareProcessRequestQuotaLimit( 375 b, 376 ts, 377 map[string]interface{}{ 378 "quota_max": -1, 379 "rate": 10000, 380 "per": 1, 381 }, 382 ) 383 384 for i := 0; i < b.N; i++ { 385 ts.Run(b, test.TestCase{ 386 Code: http.StatusOK, 387 }) 388 } 389 }