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.
Lidarr/src/NzbDrone.Common.Test/TPLTests/RateLimitServiceFixture.cs

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));
}
}
}