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  }`