/// <summary> /// Initializes a new instance of <see cref="InMemoryTokenBucketConsumer"/> class. /// </summary> /// <param name="configuration"> /// The request rate limiter configuration. /// </param> /// <param name="logger"> /// The logger. /// </param> public InMemoryTokenBucketConsumer( RequestRateLimiterConfiguration configuration, ILogger <InMemoryTokenBucketConsumer> logger) { _configuration = configuration; _logger = logger; }
/// <summary> /// Initializes a new instance of <see cref="RedisTokenBucketConsumer"/> class. /// </summary> /// <param name="redisClient"> /// The Redis API client. /// </param> /// <param name="configuration"> /// The request rate limiter configuration. /// </param> /// <param name="logger"> /// The logger. /// </param> public RedisTokenBucketConsumer( IConnectionMultiplexer redisClient, RequestRateLimiterConfiguration configuration, ILogger <RedisTokenBucketConsumer> logger) { _redisClient = redisClient; _configuration = configuration; _logger = logger; }
public void ConfigurationValidatedWhileUsingDefaultOptions() { // Given var configuration = new RequestRateLimiterConfiguration(); // When configuration is validated var exception = Record.Exception(() => configuration.Validate()); // Then it should successfully validate exception.Should().BeNull(); }
public void ConfigurationValidatedWithBurstingSetToZero() { // Given var configuration = new RequestRateLimiterConfiguration { Bursting = 0 }; // When configuration is validated var exception = Record.Exception(() => configuration.Validate()); // Then it should throw ArgumentOutOfRangeException exception.Should().NotBeNull(); exception.Should().BeOfType <ArgumentOutOfRangeException>(); exception.Message.Should().Contain("Bursting must be greater than 0."); ((ArgumentOutOfRangeException)exception).ParamName.Should().Be("Bursting"); }
public void ConfigurationValidatedWithKeysPrefixSetToNull() { // Given var configuration = new RequestRateLimiterConfiguration { KeysPrefix = null }; // When configuration is validated var exception = Record.Exception(() => configuration.Validate()); // Then it should throw ArgumentNullException exception.Should().NotBeNull(); exception.Should().BeOfType <ArgumentNullException>(); exception.Message.Should().Contain("Keys prefix must be provided."); ((ArgumentNullException)exception).ParamName.Should().Be("KeysPrefix"); }
public async void ATokenIsConsumedForTheFirstTime() { // Given const string ClientId = "tester"; const int Requested = 1; var configuration = new RequestRateLimiterConfiguration(); var loggerMock = new Mock <ILogger <InMemoryTokenBucketConsumer> >(); var consumer = new InMemoryTokenBucketConsumer(configuration, loggerMock.Object); var capacity = configuration.AverageRate * configuration.Bursting; // When a token is consumed var response = await consumer.ConsumeAsync(ClientId, Requested); // Then it should allow token consumption response.IsAllowed.Should().BeTrue(); response.Limit.Should().Be(capacity); response.Remaining.Should().Be(capacity - 1); }
public async void UnexpectedExceptionThrownByRedis() { // Given var connectionMultplexerMock = new Mock <IConnectionMultiplexer>(); var configuration = new RequestRateLimiterConfiguration(); var loggerMock = new Mock <ILogger <RedisTokenBucketConsumer> >(); connectionMultplexerMock.Setup(mock => mock.GetDatabase( Moq.It.IsAny <int>(), Moq.It.IsAny <object>())) .Throws <Exception>(); var consumer = new RedisTokenBucketConsumer( connectionMultplexerMock.Object, configuration, loggerMock.Object); // When a request is consumed var result = await consumer.ConsumeAsync( Guid.NewGuid().ToString(), 1); // Then it should log a warning loggerMock.Verify(mock => mock.Log( LogLevel.Warning, Moq.It.IsAny <EventId>(), Moq.It.IsAny <FormattedLogValues>(), Moq.It.IsAny <Exception>(), Moq.It.IsAny <Func <object, Exception, string> >())); // And it should allow the request var capacity = configuration.AverageRate * configuration.Bursting; result.IsAllowed.Should().BeTrue(); result.Limit.Should().Be(capacity); result.Remaining.Should().Be(capacity - 1); }