You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.0 KiB
127 lines
4.0 KiB
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Diagnostics;
|
|
using FluentAssertions;
|
|
using NUnit.Framework;
|
|
using NzbDrone.Common.Cache;
|
|
using NzbDrone.Common.TPL;
|
|
using NzbDrone.Test.Common;
|
|
|
|
namespace NzbDrone.Common.Test.TPLTests
|
|
{
|
|
[TestFixture]
|
|
[Platform(Exclude = "MacOsX")]
|
|
public class RateLimitServiceFixture : TestBase<RateLimitService>
|
|
{
|
|
private DateTime _epoch;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
// Make sure it's there so we don't affect measurements.
|
|
Subject.GetType();
|
|
|
|
_epoch = DateTime.UtcNow;
|
|
}
|
|
|
|
private ConcurrentDictionary<string, DateTime> GetRateLimitStore()
|
|
{
|
|
var cache = Mocker.Resolve<ICacheManager>()
|
|
.GetCache<ConcurrentDictionary<string, DateTime>>(typeof(RateLimitService), "rateLimitStore");
|
|
|
|
return cache.Get("rateLimitStore", () => new ConcurrentDictionary<string, DateTime>());
|
|
}
|
|
|
|
private void GivenExisting(string key, DateTime dateTime)
|
|
{
|
|
GetRateLimitStore().AddOrUpdate(key, dateTime, (s, i) => dateTime);
|
|
}
|
|
|
|
[Test]
|
|
public void should_not_delay_if_unset()
|
|
{
|
|
var watch = Stopwatch.StartNew();
|
|
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
|
watch.Stop();
|
|
|
|
watch.ElapsedMilliseconds.Should().BeLessThan(100);
|
|
}
|
|
|
|
[Test]
|
|
public void should_not_delay_unrelated_key()
|
|
{
|
|
GivenExisting("other", _epoch + TimeSpan.FromMilliseconds(200));
|
|
|
|
var watch = Stopwatch.StartNew();
|
|
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
|
watch.Stop();
|
|
|
|
watch.ElapsedMilliseconds.Should().BeLessThan(50);
|
|
}
|
|
|
|
[Test]
|
|
[Retry(3)]
|
|
public void should_wait_for_existing()
|
|
{
|
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
|
|
|
var watch = Stopwatch.StartNew();
|
|
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(400));
|
|
watch.Stop();
|
|
|
|
watch.ElapsedMilliseconds.Should().BeInRange(175, 250);
|
|
}
|
|
|
|
[Test]
|
|
public void should_extend_delay()
|
|
{
|
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
|
|
|
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
|
|
|
(GetRateLimitStore()["me"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(300));
|
|
}
|
|
|
|
[Test]
|
|
public void should_add_delay()
|
|
{
|
|
Subject.WaitAndPulse("me", TimeSpan.FromMilliseconds(100));
|
|
|
|
(GetRateLimitStore()["me"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(100));
|
|
}
|
|
|
|
[Test]
|
|
public void should_extend_subkey_delay()
|
|
{
|
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
|
GivenExisting("me-sub", _epoch + TimeSpan.FromMilliseconds(300));
|
|
|
|
Subject.WaitAndPulse("me", "sub", TimeSpan.FromMilliseconds(100));
|
|
|
|
(GetRateLimitStore()["me-sub"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(400));
|
|
}
|
|
|
|
[Test]
|
|
public void should_honor_basekey_delay()
|
|
{
|
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
|
GivenExisting("me-sub", _epoch + TimeSpan.FromMilliseconds(0));
|
|
|
|
Subject.WaitAndPulse("me", "sub", TimeSpan.FromMilliseconds(100));
|
|
|
|
(GetRateLimitStore()["me-sub"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(200));
|
|
}
|
|
|
|
[Test]
|
|
public void should_not_extend_basekey_delay()
|
|
{
|
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
|
GivenExisting("me-sub", _epoch + TimeSpan.FromMilliseconds(100));
|
|
|
|
Subject.WaitAndPulse("me", "sub", TimeSpan.FromMilliseconds(100));
|
|
|
|
(GetRateLimitStore()["me"] - _epoch).Should().BeCloseTo(TimeSpan.FromMilliseconds(200));
|
|
}
|
|
}
|
|
}
|