Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit unlimited ratelimits #261

Merged
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [Example 2](#example-2)
- [Example 3](#example-3)
- [Example 4](#example-4)
- [Example 5](#example-5)
- [Loading Configuration](#loading-configuration)
- [Log Format](#log-format)
- [Request Fields](#request-fields)
Expand Down Expand Up @@ -329,6 +330,25 @@ descriptors:
unit: second
```

#### Example 5

We can also define unlimited rate limit descriptors:

```yaml
domain: internal
descriptors:
- key: ldap
rate_limit:
unlimited: true

- key: azure
rate_limit:
unit: minute
requests_per_unit: 100
```

For an unlimited descriptor, the request will not be sent to the underlying cache (Redis/Memcached), but will be quickly returned locally by the ratelimit instance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you mention why someone would want to do this? I assume for stats, etc.?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, stats yes. But also, in our case, our client will not allow a request to go through if a descriptor is not found, so we do have to have it defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add something to the readme

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added


## Loading Configuration

The Ratelimit service uses a library written by Lyft called [goruntime](https://github.com/lyft/goruntime) to do configuration loading. Goruntime monitors
Expand Down
6 changes: 6 additions & 0 deletions examples/ratelimit/config/example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,9 @@ descriptors:
rate_limit:
unit: second
requests_per_unit: 1
- key: bay
rate_limit:
unlimited: true
- key: qux
rate_limit:
unlimited: true
7 changes: 4 additions & 3 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ func (e RateLimitConfigError) Error() string {

// Wrapper for an individual rate limit config entry which includes the defined limit and stats.
type RateLimit struct {
FullKey string
Stats stats.RateLimitStats
Limit *pb.RateLimitResponse_RateLimit
FullKey string
Stats stats.RateLimitStats
Limit *pb.RateLimitResponse_RateLimit
Unlimited bool
}

// Interface for interacting with a loaded rate limit config.
Expand Down
22 changes: 15 additions & 7 deletions src/config/config_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
type yamlRateLimit struct {
RequestsPerUnit uint32 `yaml:"requests_per_unit"`
Unit string
Unlimited bool `yaml:"unlimited"`
}

type yamlDescriptor struct {
Expand Down Expand Up @@ -51,17 +52,19 @@ var validKeys = map[string]bool{
"rate_limit": true,
"unit": true,
"requests_per_unit": true,
"unlimited": true,
}

// Create a new rate limit config entry.
// @param requestsPerUnit supplies the requests per unit of time for the entry.
// @param unit supplies the unit of time for the entry.
// @param rlStats supplies the stats structure associated with the RateLimit
// @param unlimited supplies whether the rate limit is unlimited
// @return the new config entry.
func NewRateLimit(
requestsPerUnit uint32, unit pb.RateLimitResponse_RateLimit_Unit, rlStats stats.RateLimitStats) *RateLimit {
requestsPerUnit uint32, unit pb.RateLimitResponse_RateLimit_Unit, rlStats stats.RateLimitStats, unlimited bool) *RateLimit {

return &RateLimit{FullKey: rlStats.GetKey(), Stats: rlStats, Limit: &pb.RateLimitResponse_RateLimit{RequestsPerUnit: requestsPerUnit, Unit: unit}}
return &RateLimit{FullKey: rlStats.GetKey(), Stats: rlStats, Limit: &pb.RateLimitResponse_RateLimit{RequestsPerUnit: requestsPerUnit, Unit: unit}, Unlimited: unlimited}
}

// Dump an individual descriptor for debugging purposes.
Expand Down Expand Up @@ -112,19 +115,21 @@ func (this *rateLimitDescriptor) loadDescriptors(config RateLimitConfigToLoad, p
var rateLimit *RateLimit = nil
var rateLimitDebugString string = ""
if descriptorConfig.RateLimit != nil {
unlimited := descriptorConfig.RateLimit.Unlimited

value, present :=
pb.RateLimitResponse_RateLimit_Unit_value[strings.ToUpper(descriptorConfig.RateLimit.Unit)]
if !present || value == int32(pb.RateLimitResponse_RateLimit_UNKNOWN) {
if (!present || value == int32(pb.RateLimitResponse_RateLimit_UNKNOWN)) && !unlimited {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you split this logic out so that we actually check if unlimited is set with a unit at all and have an error message (and test) for that? I think that would be more clear to the user.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Ping on this)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't too sure what exactly you meant, so please review this again :)

panic(newRateLimitConfigError(
config,
fmt.Sprintf("invalid rate limit unit '%s'", descriptorConfig.RateLimit.Unit)))
}

rateLimit = NewRateLimit(
descriptorConfig.RateLimit.RequestsPerUnit, pb.RateLimitResponse_RateLimit_Unit(value), statsManager.NewStats(newParentKey))
descriptorConfig.RateLimit.RequestsPerUnit, pb.RateLimitResponse_RateLimit_Unit(value), statsManager.NewStats(newParentKey), unlimited)
rateLimitDebugString = fmt.Sprintf(
" ratelimit={requests_per_unit=%d, unit=%s}", rateLimit.Limit.RequestsPerUnit,
rateLimit.Limit.Unit.String())
" ratelimit={requests_per_unit=%d, unit=%s, unlimited=%t}", rateLimit.Limit.RequestsPerUnit,
rateLimit.Limit.Unit.String(), rateLimit.Unlimited)
}

logger.Debugf(
Expand Down Expand Up @@ -167,6 +172,8 @@ func validateYamlKeys(config RateLimitConfigToLoad, config_map map[interface{}]i
case string:
// int is a leaf type in ratelimit config. No need to keep validating.
case int:
// bool is a leaf type in ratelimit config. No need to keep validating.
case bool:
// nil case is an incorrectly formed yaml. However, because this function's purpose is to validate
// the yaml's keys we don't panic here.
case nil:
Expand Down Expand Up @@ -240,7 +247,8 @@ func (this *rateLimitConfigImpl) GetLimit(
rateLimit = NewRateLimit(
descriptor.GetLimit().GetRequestsPerUnit(),
rateLimitOverrideUnit,
this.statsManager.NewStats(rateLimitKey))
this.statsManager.NewStats(rateLimitKey),
false)
return rateLimit
}

Expand Down
2 changes: 1 addition & 1 deletion src/memcached/cache_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (this *rateLimitMemcacheImpl) increaseAsync(cacheKeys []limiter.CacheKey, i
limits []*config.RateLimit, hitsAddend uint64) {
defer this.waitGroup.Done()
for i, cacheKey := range cacheKeys {
if cacheKey.Key == "" || isOverLimitWithLocalCache[i] {
if cacheKey.Key == "" || isOverLimitWithLocalCache[i] || limits[i].Unlimited {
lmajercak-wish marked this conversation as resolved.
Show resolved Hide resolved
continue
}

Expand Down
48 changes: 36 additions & 12 deletions src/service/ratelimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,15 @@ func checkServiceErr(something bool, msg string) {
}
}

func (this *service) shouldRateLimitWorker(
ctx context.Context, request *pb.RateLimitRequest) *pb.RateLimitResponse {

checkServiceErr(request.Domain != "", "rate limit domain must not be empty")
checkServiceErr(len(request.Descriptors) != 0, "rate limit descriptor list must not be empty")

func (this *service) constructLimitsToCheck(request *pb.RateLimitRequest, ctx context.Context) ([]*config.RateLimit, []bool) {
snappedConfig := this.GetCurrentConfig()
checkServiceErr(snappedConfig != nil, "no rate limit configuration loaded")

limitsToCheck := make([]*config.RateLimit, len(request.Descriptors))
isUnlimited := make([]bool, len(request.Descriptors))

for i, descriptor := range request.Descriptors {
if logger.IsLevelEnabled(logger.DebugLevel) {
var descriptorEntryStrings []string
Expand All @@ -102,14 +101,33 @@ func (this *service) shouldRateLimitWorker(
if limitsToCheck[i] == nil {
logger.Debugf("descriptor does not match any limit, no limits applied")
} else {
logger.Debugf(
"applying limit: %d requests per %s",
limitsToCheck[i].Limit.RequestsPerUnit,
limitsToCheck[i].Limit.Unit.String(),
)
if limitsToCheck[i].Unlimited {
logger.Debugf("descriptor is unlimited, not passing to the cache")
} else {
logger.Debugf(
"applying limit: %d requests per %s",
limitsToCheck[i].Limit.RequestsPerUnit,
limitsToCheck[i].Limit.Unit.String(),
)
}
}
}

if limitsToCheck[i] != nil && limitsToCheck[i].Unlimited {
isUnlimited[i] = true
limitsToCheck[i] = nil
}
}
return limitsToCheck, isUnlimited
}

func (this *service) shouldRateLimitWorker(
ctx context.Context, request *pb.RateLimitRequest) *pb.RateLimitResponse {

checkServiceErr(request.Domain != "", "rate limit domain must not be empty")
checkServiceErr(len(request.Descriptors) != 0, "rate limit descriptor list must not be empty")

limitsToCheck, isUnlimited := this.constructLimitsToCheck(request, ctx)

responseDescriptorStatuses := this.cache.DoLimit(ctx, request, limitsToCheck)
assert.Assert(len(limitsToCheck) == len(responseDescriptorStatuses))
Expand All @@ -118,9 +136,15 @@ func (this *service) shouldRateLimitWorker(
response.Statuses = make([]*pb.RateLimitResponse_DescriptorStatus, len(request.Descriptors))
finalCode := pb.RateLimitResponse_OK
for i, descriptorStatus := range responseDescriptorStatuses {
response.Statuses[i] = descriptorStatus
if descriptorStatus.Code == pb.RateLimitResponse_OVER_LIMIT {
finalCode = descriptorStatus.Code
if isUnlimited[i] {
response.Statuses[i] = &pb.RateLimitResponse_DescriptorStatus{
Code: pb.RateLimitResponse_OK,
}
} else {
response.Statuses[i] = descriptorStatus
if descriptorStatus.Code == pb.RateLimitResponse_OVER_LIMIT {
finalCode = descriptorStatus.Code
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions test/config/basic_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,7 @@ descriptors:
rate_limit:
unit: day
requests_per_unit: 25

- key: key6
rate_limit:
unlimited: true
11 changes: 11 additions & 0 deletions test/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ func TestBasicConfig(t *testing.T) {
assert.EqualValues(1, stats.NewCounter("test-domain.key4.over_limit").Value())
assert.EqualValues(1, stats.NewCounter("test-domain.key4.near_limit").Value())
assert.EqualValues(1, stats.NewCounter("test-domain.key4.within_limit").Value())

rl = rlConfig.GetLimit(
nil, "test-domain",
&pb_struct.RateLimitDescriptor{
Entries: []*pb_struct.RateLimitDescriptor_Entry{{Key: "key6", Value: "foo"}},
})
rl.Stats.TotalHits.Inc()
rl.Stats.WithinLimit.Inc()
assert.True(rl.Unlimited)
assert.EqualValues(1, stats.NewCounter("test-domain.key6.total_hits").Value())
assert.EqualValues(1, stats.NewCounter("test-domain.key6.within_limit").Value())
}

func TestConfigLimitOverride(t *testing.T) {
Expand Down
34 changes: 17 additions & 17 deletions test/memcached/cache_impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestMemcached(t *testing.T) {
client.EXPECT().Increment("domain_key_value_1234", uint64(1)).Return(uint64(5), nil)

request := common.NewRateLimitRequest("domain", [][][2]string{{{"key", "value"}}}, 1)
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"))}
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 5, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -70,7 +70,7 @@ func TestMemcached(t *testing.T) {
}, 1)
limits = []*config.RateLimit{
nil,
config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_MINUTE, sm.NewStats("key2_value2_subkey2_subvalue2"))}
config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_MINUTE, sm.NewStats("key2_value2_subkey2_subvalue2"), false)}
assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: nil, LimitRemaining: 0},
{Code: pb.RateLimitResponse_OVER_LIMIT, CurrentLimit: limits[1].Limit, LimitRemaining: 0, DurationUntilReset: utils.CalculateReset(limits[1].Limit, timeSource)}},
Expand Down Expand Up @@ -100,8 +100,8 @@ func TestMemcached(t *testing.T) {
{{"key3", "value3"}, {"subkey3", "subvalue3"}},
}, 1)
limits = []*config.RateLimit{
config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_HOUR, sm.NewStats("key3_value3")),
config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_DAY, sm.NewStats("key3_value3_subkey3_subvalue3"))}
config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_HOUR, sm.NewStats("key3_value3"), false),
config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_DAY, sm.NewStats("key3_value3_subkey3_subvalue3"), false)}
assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{
{Code: pb.RateLimitResponse_OVER_LIMIT, CurrentLimit: limits[0].Limit, LimitRemaining: 0, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)},
Expand Down Expand Up @@ -137,7 +137,7 @@ func TestMemcachedGetError(t *testing.T) {
client.EXPECT().Increment("domain_key_value_1234", uint64(1)).Return(uint64(5), nil)

request := common.NewRateLimitRequest("domain", [][][2]string{{{"key", "value"}}}, 1)
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"))}
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 9, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -155,7 +155,7 @@ func TestMemcachedGetError(t *testing.T) {
client.EXPECT().Increment("domain_key_value1_1234", uint64(1)).Return(uint64(5), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key", "value1"}}}, 1)
limits = []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value1"))}
limits = []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value1"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 9, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand Down Expand Up @@ -228,7 +228,7 @@ func TestOverLimitWithLocalCache(t *testing.T) {
request := common.NewRateLimitRequest("domain", [][][2]string{{{"key4", "value4"}}}, 1)

limits := []*config.RateLimit{
config.NewRateLimit(15, pb.RateLimitResponse_RateLimit_HOUR, sm.NewStats("key4_value4"))}
config.NewRateLimit(15, pb.RateLimitResponse_RateLimit_HOUR, sm.NewStats("key4_value4"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{
Expand Down Expand Up @@ -324,7 +324,7 @@ func TestNearLimit(t *testing.T) {
request := common.NewRateLimitRequest("domain", [][][2]string{{{"key4", "value4"}}}, 1)

limits := []*config.RateLimit{
config.NewRateLimit(15, pb.RateLimitResponse_RateLimit_HOUR, sm.NewStats("key4_value4"))}
config.NewRateLimit(15, pb.RateLimitResponse_RateLimit_HOUR, sm.NewStats("key4_value4"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{
Expand Down Expand Up @@ -377,7 +377,7 @@ func TestNearLimit(t *testing.T) {
client.EXPECT().Increment("domain_key5_value5_1234", uint64(3)).Return(uint64(5), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key5", "value5"}}}, 3)
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key5_value5"))}
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key5_value5"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 15, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -395,7 +395,7 @@ func TestNearLimit(t *testing.T) {
client.EXPECT().Increment("domain_key6_value6_1234", uint64(2)).Return(uint64(7), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key6", "value6"}}}, 2)
limits = []*config.RateLimit{config.NewRateLimit(8, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key6_value6"))}
limits = []*config.RateLimit{config.NewRateLimit(8, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key6_value6"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 1, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -413,7 +413,7 @@ func TestNearLimit(t *testing.T) {
client.EXPECT().Increment("domain_key7_value7_1234", uint64(3)).Return(uint64(19), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key7", "value7"}}}, 3)
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key7_value7"))}
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key7_value7"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 1, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -431,7 +431,7 @@ func TestNearLimit(t *testing.T) {
client.EXPECT().Increment("domain_key8_value8_1234", uint64(3)).Return(uint64(22), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key8", "value8"}}}, 3)
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key8_value8"))}
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key8_value8"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OVER_LIMIT, CurrentLimit: limits[0].Limit, LimitRemaining: 0, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -449,7 +449,7 @@ func TestNearLimit(t *testing.T) {
client.EXPECT().Increment("domain_key9_value9_1234", uint64(7)).Return(uint64(22), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key9", "value9"}}}, 7)
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key9_value9"))}
limits = []*config.RateLimit{config.NewRateLimit(20, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key9_value9"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OVER_LIMIT, CurrentLimit: limits[0].Limit, LimitRemaining: 0, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -467,7 +467,7 @@ func TestNearLimit(t *testing.T) {
client.EXPECT().Increment("domain_key10_value10_1234", uint64(3)).Return(uint64(30), nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key10", "value10"}}}, 3)
limits = []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key10_value10"))}
limits = []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key10_value10"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OVER_LIMIT, CurrentLimit: limits[0].Limit, LimitRemaining: 0, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand Down Expand Up @@ -511,7 +511,7 @@ func TestMemcacheWithJitter(t *testing.T) {
).Return(nil)

request := common.NewRateLimitRequest("domain", [][][2]string{{{"key", "value"}}}, 1)
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"))}
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 9, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand Down Expand Up @@ -554,7 +554,7 @@ func TestMemcacheAdd(t *testing.T) {
uint64(2), nil)

request := common.NewRateLimitRequest("domain", [][][2]string{{{"key", "value"}}}, 1)
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"))}
limits := []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_SECOND, sm.NewStats("key_value"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 9, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand All @@ -578,7 +578,7 @@ func TestMemcacheAdd(t *testing.T) {
).Return(nil)

request = common.NewRateLimitRequest("domain", [][][2]string{{{"key2", "value2"}}}, 1)
limits = []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_MINUTE, sm.NewStats("key2_value2"))}
limits = []*config.RateLimit{config.NewRateLimit(10, pb.RateLimitResponse_RateLimit_MINUTE, sm.NewStats("key2_value2"), false)}

assert.Equal(
[]*pb.RateLimitResponse_DescriptorStatus{{Code: pb.RateLimitResponse_OK, CurrentLimit: limits[0].Limit, LimitRemaining: 9, DurationUntilReset: utils.CalculateReset(limits[0].Limit, timeSource)}},
Expand Down
Loading