github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/mw_api_rate_limit_test.go (about) 1 package gateway 2 3 import ( 4 "net/http" 5 "net/http/httptest" 6 "net/url" 7 "testing" 8 "time" 9 10 "github.com/TykTechnologies/tyk/config" 11 "github.com/TykTechnologies/tyk/test" 12 uuid "github.com/satori/go.uuid" 13 14 "github.com/justinas/alice" 15 16 "github.com/TykTechnologies/tyk/user" 17 ) 18 19 func createRLSession() *user.SessionState { 20 session := new(user.SessionState) 21 // essentially non-throttled 22 session.Rate = 100.0 23 session.Allowance = session.Rate 24 session.LastCheck = time.Now().Unix() 25 session.Per = 1.0 26 session.QuotaRenewalRate = 300 // 5 minutes 27 session.QuotaRenews = time.Now().Unix() 28 session.QuotaRemaining = 10 29 session.QuotaMax = 10 30 session.AccessRights = map[string]user.AccessDefinition{"31445455": {APIName: "Tyk Auth Key Test", APIID: "31445455", Versions: []string{"default"}}} 31 return session 32 } 33 34 func getRLOpenChain(spec *APISpec) http.Handler { 35 remote, _ := url.Parse(spec.Proxy.TargetURL) 36 proxy := TykNewSingleHostReverseProxy(remote, spec) 37 proxyHandler := ProxyHandler(proxy, spec) 38 baseMid := BaseMiddleware{Spec: spec, Proxy: proxy} 39 chain := alice.New(mwList( 40 &IPWhiteListMiddleware{baseMid}, 41 &IPBlackListMiddleware{BaseMiddleware: baseMid}, 42 &VersionCheck{BaseMiddleware: baseMid}, 43 &RateLimitForAPI{BaseMiddleware: baseMid}, 44 )...).Then(proxyHandler) 45 return chain 46 } 47 48 func getGlobalRLAuthKeyChain(spec *APISpec) http.Handler { 49 remote, _ := url.Parse(spec.Proxy.TargetURL) 50 proxy := TykNewSingleHostReverseProxy(remote, spec) 51 proxyHandler := ProxyHandler(proxy, spec) 52 baseMid := BaseMiddleware{Spec: spec, Proxy: proxy} 53 chain := alice.New(mwList( 54 &IPWhiteListMiddleware{baseMid}, 55 &IPBlackListMiddleware{BaseMiddleware: baseMid}, 56 &AuthKey{baseMid}, 57 &VersionCheck{BaseMiddleware: baseMid}, 58 &KeyExpired{baseMid}, 59 &AccessRightsCheck{baseMid}, 60 &RateLimitForAPI{BaseMiddleware: baseMid}, 61 &RateLimitAndQuotaCheck{baseMid}, 62 )...).Then(proxyHandler) 63 return chain 64 } 65 66 func TestRLOpen(t *testing.T) { 67 spec := CreateSpecTest(t, openRLDefSmall) 68 69 req := TestReq(t, "GET", "/rl_test/", nil) 70 71 DRLManager.CurrentTokenValue = 1 72 DRLManager.RequestTokenValue = 1 73 74 chain := getRLOpenChain(spec) 75 for a := 0; a <= 10; a++ { 76 recorder := httptest.NewRecorder() 77 chain.ServeHTTP(recorder, req) 78 if a < 3 { 79 if recorder.Code != 200 { 80 t.Fatalf("Rate limit kicked in too early, after only %v requests", a) 81 } 82 } 83 84 if a > 7 { 85 if recorder.Code != 429 { 86 t.Fatalf("Rate limit did not activate, code was: %v", recorder.Code) 87 } 88 } 89 } 90 91 DRLManager.CurrentTokenValue = 0 92 DRLManager.RequestTokenValue = 0 93 } 94 95 func requestThrottlingTest(limiter string, testLevel string) func(t *testing.T) { 96 return func(t *testing.T) { 97 defer ResetTestConfig() 98 99 ts := StartTest() 100 defer ts.Close() 101 102 globalCfg := config.Global() 103 104 switch limiter { 105 case "InMemoryRateLimiter": 106 DRLManager.CurrentTokenValue = 1 107 DRLManager.RequestTokenValue = 1 108 case "SentinelRateLimiter": 109 globalCfg.EnableSentinelRateLimiter = true 110 case "RedisRollingRateLimiter": 111 globalCfg.EnableRedisRollingLimiter = true 112 default: 113 t.Fatal("There is no such a rate limiter:", limiter) 114 } 115 116 config.SetGlobal(globalCfg) 117 118 var per, rate, throttleInterval float64 119 var throttleRetryLimit int 120 121 per = 2 122 rate = 1 123 throttleInterval = 1 124 throttleRetryLimit = 3 125 126 for _, requestThrottlingEnabled := range []bool{false, true} { 127 128 spec := BuildAndLoadAPI(func(spec *APISpec) { 129 spec.Name = "test" 130 spec.APIID = "test" 131 spec.OrgID = "default" 132 spec.UseKeylessAccess = false 133 spec.Proxy.ListenPath = "/" 134 })[0] 135 136 policyID := CreatePolicy(func(p *user.Policy) { 137 p.OrgID = "default" 138 139 p.AccessRights = map[string]user.AccessDefinition{ 140 spec.APIID: { 141 APIName: spec.APIDefinition.Name, 142 APIID: spec.APIID, 143 }, 144 } 145 146 if testLevel == "PolicyLevel" { 147 p.Per = per 148 p.Rate = rate 149 150 if requestThrottlingEnabled { 151 p.ThrottleInterval = throttleInterval 152 p.ThrottleRetryLimit = throttleRetryLimit 153 } 154 } else if testLevel == "APILevel" { 155 a := p.AccessRights[spec.APIID] 156 a.Limit = &user.APILimit{ 157 Rate: rate, 158 Per: per, 159 } 160 161 if requestThrottlingEnabled { 162 a.Limit.ThrottleInterval = throttleInterval 163 a.Limit.ThrottleRetryLimit = throttleRetryLimit 164 } 165 166 p.AccessRights[spec.APIID] = a 167 } else { 168 t.Fatal("There is no such a test level:", testLevel) 169 } 170 }) 171 172 key := CreateSession(func(s *user.SessionState) { 173 s.ApplyPolicies = []string{policyID} 174 }) 175 176 authHeaders := map[string]string{ 177 "authorization": key, 178 } 179 180 if requestThrottlingEnabled { 181 ts.Run(t, []test.TestCase{ 182 {Path: "/", Headers: authHeaders, Code: 200, Delay: 100 * time.Millisecond}, 183 {Path: "/", Headers: authHeaders, Code: 200}, 184 }...) 185 } else { 186 ts.Run(t, []test.TestCase{ 187 {Path: "/", Headers: authHeaders, Code: 200, Delay: 100 * time.Millisecond}, 188 {Path: "/", Headers: authHeaders, Code: 429}, 189 }...) 190 } 191 192 } 193 } 194 } 195 196 func TestRequestThrottling(t *testing.T) { 197 t.Run("PolicyLevel", func(t *testing.T) { 198 t.Run("InMemoryRateLimiter", requestThrottlingTest("InMemoryRateLimiter", "PolicyLevel")) 199 t.Run("SentinelRateLimiter", requestThrottlingTest("SentinelRateLimiter", "PolicyLevel")) 200 t.Run("RedisRollingRateLimiter", requestThrottlingTest("RedisRollingRateLimiter", "PolicyLevel")) 201 }) 202 203 t.Run("APILevel", func(t *testing.T) { 204 t.Run("InMemoryRateLimiter", requestThrottlingTest("InMemoryRateLimiter", "APILevel")) 205 t.Run("SentinelRateLimiter", requestThrottlingTest("SentinelRateLimiter", "APILevel")) 206 t.Run("RedisRollingRateLimiter", requestThrottlingTest("RedisRollingRateLimiter", "APILevel")) 207 }) 208 209 } 210 211 func TestRLClosed(t *testing.T) { 212 spec := CreateSpecTest(t, closedRLDefSmall) 213 214 req := TestReq(t, "GET", "/rl_closed_test/", nil) 215 216 session := createRLSession() 217 customToken := uuid.NewV4().String() 218 // AuthKey sessions are stored by {token} 219 spec.SessionManager.UpdateSession(customToken, session, 60, false) 220 req.Header.Set("authorization", "Bearer "+customToken) 221 222 DRLManager.CurrentTokenValue = 1 223 DRLManager.RequestTokenValue = 1 224 225 chain := getGlobalRLAuthKeyChain(spec) 226 for a := 0; a <= 10; a++ { 227 recorder := httptest.NewRecorder() 228 chain.ServeHTTP(recorder, req) 229 if a < 3 { 230 if recorder.Code != 200 { 231 t.Fatalf("Rate limit kicked in too early, after only %v requests", a) 232 } 233 } 234 235 if a > 7 { 236 if recorder.Code != 429 { 237 t.Fatalf("Rate limit did not activate, code was: %v", recorder.Code) 238 } 239 } 240 } 241 242 DRLManager.CurrentTokenValue = 0 243 DRLManager.RequestTokenValue = 0 244 } 245 246 func TestRLOpenWithReload(t *testing.T) { 247 spec := CreateSpecTest(t, openRLDefSmall) 248 249 req := TestReq(t, "GET", "/rl_test/", nil) 250 251 DRLManager.CurrentTokenValue = 1 252 DRLManager.RequestTokenValue = 1 253 254 chain := getRLOpenChain(spec) 255 for a := 0; a <= 10; a++ { 256 recorder := httptest.NewRecorder() 257 chain.ServeHTTP(recorder, req) 258 if a < 3 { 259 if recorder.Code != 200 { 260 t.Fatalf("Rate limit (pre change) kicked in too early, after only %v requests", a) 261 } 262 } 263 264 if a > 7 { 265 if recorder.Code != 429 { 266 t.Fatalf("Rate limit (pre change) did not activate, code was: %v", recorder.Code) 267 } 268 } 269 } 270 271 // Change rate and emulate a reload 272 spec.GlobalRateLimit.Rate = 20 273 chain = getRLOpenChain(spec) 274 for a := 0; a <= 30; a++ { 275 recorder := httptest.NewRecorder() 276 chain.ServeHTTP(recorder, req) 277 if a < 20 { 278 if recorder.Code != 200 { 279 t.Fatalf("Rate limit (post change) kicked in too early, after only %v requests", a) 280 } 281 } 282 283 if a > 23 { 284 if recorder.Code != 429 { 285 t.Fatalf("Rate limit (post change) did not activate, code was: %v", recorder.Code) 286 } 287 } 288 } 289 290 DRLManager.CurrentTokenValue = 0 291 DRLManager.RequestTokenValue = 0 292 } 293 294 const openRLDefSmall = `{ 295 "api_id": "313232", 296 "org_id": "default", 297 "auth": {"auth_header_name": "authorization"}, 298 "use_keyless": true, 299 "version_data": { 300 "not_versioned": true, 301 "versions": { 302 "v1": {"name": "v1"} 303 } 304 }, 305 "proxy": { 306 "listen_path": "/rl_test/", 307 "target_url": "` + testHttpAny + `" 308 }, 309 "global_rate_limit": { 310 "rate": 3, 311 "per": 1 312 } 313 }` 314 315 const closedRLDefSmall = `{ 316 "api_id": "31445455", 317 "org_id": "default", 318 "auth": {"auth_header_name": "authorization"}, 319 "version_data": { 320 "not_versioned": true, 321 "versions": { 322 "v1": {"name": "v1"} 323 } 324 }, 325 "proxy": { 326 "listen_path": "/rl_closed_test/", 327 "target_url": "` + testHttpAny + `" 328 }, 329 "global_rate_limit": { 330 "rate": 3, 331 "per": 1 332 } 333 }`