-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add validation rules (cooldown, max reqs), settings, and tests
- Loading branch information
1 parent
d0a5741
commit a66d1b8
Showing
13 changed files
with
702 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using RateLimiter; | ||
|
||
namespace RateLimiter.Tests | ||
{ | ||
[TestFixture] | ||
public class CooldownPeriodTests | ||
{ | ||
private CooldownPeriod _cooldownPeriod; | ||
private UserSettings _userSettings; | ||
private RuleSettings _ruleSettings; | ||
private ValidationRequest _request; | ||
|
||
[SetUp] | ||
public void Setup() | ||
{ | ||
_cooldownPeriod = new CooldownPeriod(); | ||
_userSettings = new UserSettings { Id = "user1" }; | ||
_request = new ValidationRequest { RequestTime = DateTime.UtcNow }; | ||
|
||
_ruleSettings = new RuleSettings | ||
{ | ||
Name = "CooldownPeriod", | ||
Enabled = true, | ||
Options = new List<Option>() | ||
{ | ||
new Option { Type = "Default", CooldownMsec = 1000 }, | ||
new Option { Region = "EU", CooldownMsec = 2000 }, | ||
new Option { Region = "US", CooldownMsec = 500 } | ||
} | ||
}; | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_RuleNotEnabled_ShouldPassValidation() | ||
{ | ||
_ruleSettings.Enabled = false; | ||
var result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_NoHistory_ShouldPassValidation() | ||
{ | ||
var result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_WithinCooldown_ShouldFailValidation() | ||
{ | ||
_cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
_request.RequestTime = _request.RequestTime.AddMilliseconds(500); | ||
var result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsFalse(result); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_OutsideCooldown_ShouldPassValidation() | ||
{ | ||
_cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
_request.RequestTime = _request.RequestTime.AddMilliseconds(1500); | ||
var result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_RegionOverridesDefault_ShouldUseRegionCooldown() | ||
{ | ||
_userSettings.Region = Region.EU; | ||
|
||
var result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
|
||
_request.RequestTime = _request.RequestTime.AddMilliseconds(1500); | ||
result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsFalse(result); | ||
|
||
_request.RequestTime = _request.RequestTime.AddMilliseconds(2500); | ||
result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_TierOverridesRegion_ShouldUseTierCooldown() | ||
{ | ||
_userSettings.ServiceTier = ServiceTier.Pro; | ||
|
||
_ruleSettings = new RuleSettings | ||
{ | ||
Name = "CooldownPeriod", | ||
Enabled = true, | ||
Options = new List<Option>() | ||
{ | ||
new Option { Type = "Default", CooldownMsec = 1000 }, | ||
new Option { Region = "EU", CooldownMsec = 2000 }, | ||
new Option { Tier = "Pro", CooldownMsec = 500 } | ||
} | ||
}; | ||
|
||
var result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
|
||
_request.RequestTime = _request.RequestTime.AddMilliseconds(400); | ||
result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsFalse(result); | ||
|
||
_request.RequestTime = _request.RequestTime.AddMilliseconds(600); | ||
result = _cooldownPeriod.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using RateLimiter; | ||
|
||
namespace RateLimiter.Tests | ||
{ | ||
public class MaxRequestsRollingWindowTests | ||
{ | ||
private MaxRequestsRollingWindow _maxRequestsRollingWindow; | ||
private UserSettings _userSettings; | ||
private RuleSettings _ruleSettings; | ||
private ValidationRequest _request; | ||
|
||
[SetUp] | ||
public void Setup() | ||
{ | ||
_maxRequestsRollingWindow = new MaxRequestsRollingWindow(); | ||
_userSettings = new UserSettings { Id = "user1" }; | ||
_request = new ValidationRequest { RequestTime = DateTime.UtcNow }; | ||
|
||
_ruleSettings = new RuleSettings | ||
{ | ||
Name = "MaxRequestsRollingWindow", | ||
Enabled = true, | ||
Options = new List<Option> | ||
{ | ||
new Option { Type = "Default", MaxRequests = 3, PeriodMsec = 1000 }, | ||
new Option { Region = "EU", MaxRequests = 5, PeriodMsec = 2000 }, | ||
new Option { Region = "US", MaxRequests = 10, PeriodMsec = 2000 } | ||
} | ||
}; | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_WithinLimit_ShouldPassValidation() | ||
{ | ||
for (int i = 0; i < 3; i++) | ||
{ | ||
var request = new ValidationRequest { RequestTime = _request.RequestTime.AddMilliseconds(i * 200) }; | ||
var result = _maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, request); | ||
Assert.IsTrue(result); | ||
} | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_ExceedsLimit_ShouldFailValidation() | ||
{ | ||
for (int i = 0; i < 3; i++) | ||
{ | ||
var request = new ValidationRequest { RequestTime = _request.RequestTime.AddMilliseconds(i * 200) }; | ||
_maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings,request); | ||
} | ||
|
||
_request.RequestTime = _request.RequestTime.AddMilliseconds(600); | ||
var result = _maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsFalse(result); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_RegionOverridesDefault_ShouldUseRegionSettings() | ||
{ | ||
_userSettings.Region = Region.EU; | ||
|
||
for (int i = 0; i < 5; i++) | ||
{ | ||
var request = new ValidationRequest { RequestTime = _request.RequestTime.AddMilliseconds(i * 300) }; | ||
var result = _maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, request); | ||
Assert.IsTrue(result); | ||
} | ||
|
||
_request.RequestTime = _request.RequestTime.AddMilliseconds(1500); | ||
var finalResult = _maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsFalse(finalResult); | ||
} | ||
|
||
[Test] | ||
public void ValidateRequest_RemoveOldTimestamps_ShouldPassValidation() | ||
{ | ||
var request = new ValidationRequest { RequestTime = _request.RequestTime.AddMilliseconds(-1500) }; | ||
_maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, request); | ||
|
||
request.RequestTime = _request.RequestTime.AddMilliseconds(-1000); | ||
_maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, request); | ||
|
||
request.RequestTime = _request.RequestTime.AddMilliseconds(-500); | ||
_maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, request); | ||
|
||
var result = _maxRequestsRollingWindow.ValidateRequest(_userSettings, _ruleSettings, _request); | ||
Assert.IsTrue(result); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,145 @@ | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using NSubstitute; | ||
|
||
namespace RateLimiter.Tests; | ||
|
||
[TestFixture] | ||
public class RateLimiterTest | ||
namespace RateLimiter.Tests | ||
{ | ||
[Test] | ||
public void Example() | ||
{ | ||
Assert.That(true, Is.True); | ||
} | ||
} | ||
public class RequestValidatorTests | ||
{ | ||
private RequestValidator _requestValidator; | ||
private UserSettings _userSettings; | ||
private RuleSettingsList _ruleSettings; | ||
private ValidationRequest _request; | ||
private IRequestValidatorRule _ruleMock; | ||
|
||
[SetUp] | ||
public void Setup() | ||
{ | ||
_requestValidator = new RequestValidator(); | ||
_userSettings = new UserSettings { Id = "user1" }; | ||
_request = new ValidationRequest {RequestTime = DateTime.UtcNow }; | ||
_ruleMock = Substitute.For<IRequestValidatorRule>(); | ||
_ruleSettings = new RuleSettingsList { | ||
RateLimiterRules = new List<RuleSettings>{ | ||
new RuleSettings | ||
{ | ||
Name = _ruleMock.GetType().Name, | ||
Enabled = true, | ||
Options = new List<Option>() | ||
} | ||
} | ||
}; | ||
} | ||
|
||
[Test] | ||
public void CheckRules_NoRulesProvided_ReturnsTrue() | ||
{ | ||
var rules = new List<IRequestValidatorRule>(); | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_RuleWithNoMatchingSettings_ReturnsFalse() | ||
{ | ||
var rule = Substitute.For<IRequestValidatorRule>(); | ||
var rules = new List<IRequestValidatorRule> { rule }; | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsFalse(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_RuleWithMatchingSettingsButNoOptions_ReturnsFalse() | ||
{ | ||
var rule = Substitute.For<IRequestValidatorRule>(); | ||
var rules = new List<IRequestValidatorRule> { rule }; | ||
var ruleName = rule.GetType().Name; | ||
_ruleSettings.RateLimiterRules.Add(new RuleSettings { Name = ruleName, Enabled = true, Options = null }); | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsFalse(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_RuleIsNotEnabled_SkipsRule() | ||
{ | ||
var rule = Substitute.For<IRequestValidatorRule>(); | ||
var rules = new List<IRequestValidatorRule> { rule }; | ||
var ruleName = rule.GetType().Name; | ||
_ruleSettings.RateLimiterRules.Clear(); | ||
_ruleSettings.RateLimiterRules.Add(new RuleSettings { Name = ruleName, Enabled = false, Options = new List<Option>() }); | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_AllRulesValid_ShouldReturnTrue() | ||
{ | ||
_ruleMock.ValidateRequest(_userSettings, Arg.Any<RuleSettings>(), _request).Returns(true); | ||
|
||
var rules = new List<IRequestValidatorRule> { _ruleMock, _ruleMock, _ruleMock }; | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_OneRuleInvalid_ShouldReturnFalse() | ||
{ | ||
_ruleMock.ValidateRequest(_userSettings, Arg.Any<RuleSettings>(), _request).Returns(true, false, true); | ||
|
||
var rules = new List<IRequestValidatorRule> { _ruleMock, _ruleMock, _ruleMock }; | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsFalse(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_NoRules_ShouldReturnTrue() | ||
{ | ||
var rules = new List<IRequestValidatorRule>(); | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsTrue(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_FirstRuleInvalid_ShouldReturnFalse() | ||
{ | ||
_ruleMock.ValidateRequest(_userSettings, Arg.Any<RuleSettings>(), _request).Returns(false); | ||
|
||
var rules = new List<IRequestValidatorRule> { _ruleMock }; | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsFalse(result); | ||
} | ||
|
||
[Test] | ||
public void CheckRules_MixedValidInvalidRules_ShouldReturnFalse() | ||
{ | ||
var validRuleMock = Substitute.For<IRequestValidatorRule>(); | ||
var invalidRuleMock = Substitute.For<IRequestValidatorRule>(); | ||
|
||
validRuleMock.ValidateRequest(_userSettings, Arg.Any<RuleSettings>(), _request).Returns(true); | ||
invalidRuleMock.ValidateRequest(_userSettings, Arg.Any<RuleSettings>(), _request).Returns(false); | ||
|
||
var rules = new List<IRequestValidatorRule> { validRuleMock, invalidRuleMock, validRuleMock }; | ||
|
||
var result = _requestValidator.CheckRules(_userSettings, _ruleSettings, rules, _request); | ||
|
||
Assert.IsFalse(result); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using System; | ||
|
||
namespace RateLimiter; | ||
|
||
public interface IRequestValidatorRule | ||
{ | ||
public bool ValidateRequest(UserSettings user, RuleSettings settings, ValidationRequest request); | ||
} |
Oops, something went wrong.