Skip to content

Commit b2eabc4

Browse files
authored
Merge pull request #816 from FinnReilly/feature/addTestsToRateLimitingCodeAndResolveAnyBugs
Feature/add tests to rate limiting code and resolve any bugs
2 parents a35b460 + 4e59c77 commit b2eabc4

File tree

6 files changed

+81
-9
lines changed

6 files changed

+81
-9
lines changed

Amazon-SP-API-CSharp.sln

+7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FikaAmazonAPI.SampleCode",
1818
EndProject
1919
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FikaAmazonAPI", "Source\FikaAmazonAPI\FikaAmazonAPI.csproj", "{D6BE954D-174D-4C19-A0B6-46F020878E72}"
2020
EndProject
21+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Source\Tests\Tests.csproj", "{4CB44101-8A9E-454A-B272-038C5FAF9F23}"
22+
EndProject
2123
Global
2224
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2325
Debug|Any CPU = Debug|Any CPU
@@ -32,13 +34,18 @@ Global
3234
{D6BE954D-174D-4C19-A0B6-46F020878E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
3335
{D6BE954D-174D-4C19-A0B6-46F020878E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
3436
{D6BE954D-174D-4C19-A0B6-46F020878E72}.Release|Any CPU.Build.0 = Release|Any CPU
37+
{4CB44101-8A9E-454A-B272-038C5FAF9F23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38+
{4CB44101-8A9E-454A-B272-038C5FAF9F23}.Debug|Any CPU.Build.0 = Debug|Any CPU
39+
{4CB44101-8A9E-454A-B272-038C5FAF9F23}.Release|Any CPU.ActiveCfg = Release|Any CPU
40+
{4CB44101-8A9E-454A-B272-038C5FAF9F23}.Release|Any CPU.Build.0 = Release|Any CPU
3541
EndGlobalSection
3642
GlobalSection(SolutionProperties) = preSolution
3743
HideSolutionNode = FALSE
3844
EndGlobalSection
3945
GlobalSection(NestedProjects) = preSolution
4046
{FC494085-19C4-4835-B053-F9B74FFB978A} = {3472E85C-6C29-4196-AA16-B95898241C04}
4147
{D6BE954D-174D-4C19-A0B6-46F020878E72} = {3472E85C-6C29-4196-AA16-B95898241C04}
48+
{4CB44101-8A9E-454A-B272-038C5FAF9F23} = {3472E85C-6C29-4196-AA16-B95898241C04}
4249
EndGlobalSection
4350
GlobalSection(ExtensibilityGlobals) = postSolution
4451
SolutionGuid = {F072E7DD-BF35-43CC-BF83-E5947CA2D772}

Source/FikaAmazonAPI.SampleCode/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static async Task Main(string[] args)
2020
RefreshToken: config.GetSection("FikaAmazonAPI:RefreshToken").Value,
2121
rateLimitingHandler: new RateLimitingHandler());
2222

23-
var tasks = new[] { 1..10 }.Select(x =>
23+
var tasks = Enumerable.Range(1, 10).Select(x =>
2424
Task.Run(() =>
2525
{
2626
var amazonConnection = connectionFactory.RequestScopedConnection(

Source/FikaAmazonAPI/Utils/RateLimits.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
using System;
2-
using System.Runtime;
2+
using System.Runtime.CompilerServices;
33
using System.Threading;
44
using System.Threading.Tasks;
55

6+
[assembly: InternalsVisibleTo("Tests")]
67
namespace FikaAmazonAPI.Utils
78
{
89
internal class RateLimits
@@ -47,10 +48,9 @@ public async Task WaitForPermittedRequest(CancellationToken cancellationToken =
4748
}
4849

4950
int ratePeriodMs = GetRatePeriodMs();
50-
var requestsUsedAtOnset = RequestsUsed;
5151

5252
// when requests used more than zero, replenish according to time elapsed
53-
IncrementAvailableTokens(debugMode);
53+
DecrementRequestsUsed(debugMode);
5454

5555
var nextRequestsSent = RequestsUsed + 1;
5656
var nextRequestsSentTxt = (nextRequestsSent > Burst) ? "FULL" : nextRequestsSent.ToString();
@@ -76,7 +76,7 @@ public async Task WaitForPermittedRequest(CancellationToken cancellationToken =
7676
else
7777
{
7878
// replenish token
79-
IncrementAvailableTokens(debugMode);
79+
DecrementRequestsUsed(debugMode);
8080
}
8181

8282
if (RequestsUsed <= 0)
@@ -87,7 +87,7 @@ public async Task WaitForPermittedRequest(CancellationToken cancellationToken =
8787
}
8888

8989
// now remove token from bucket for pending request
90-
requestIsPermitted = TryDecrementAvailableTokens(debugMode);
90+
requestIsPermitted = TryIncrementRequestsUsed(debugMode);
9191
}
9292
}
9393

@@ -97,13 +97,13 @@ internal void SetRateLimit(decimal rate)
9797
}
9898

9999
// increments available tokens, unless another thread has already incremented them.
100-
private void IncrementAvailableTokens(bool isDebug)
100+
private void DecrementRequestsUsed(bool isDebug)
101101
{
102102
WriteDebug($"Attempting to increment tokens", isDebug);
103103
lock (_locker)
104104
{
105105
var ratePeriodMilliseconds = GetRatePeriodMs();
106-
var requestsToReplenish = ratePeriodMilliseconds == 0 ? 0 : (DateTime.UtcNow - LastRequestReplenished).Milliseconds / ratePeriodMilliseconds;
106+
var requestsToReplenish = ratePeriodMilliseconds == 0 ? 0 : (int)((DateTime.UtcNow - LastRequestReplenished).TotalMilliseconds / ratePeriodMilliseconds);
107107
WriteDebug($"{requestsToReplenish} tokens to replenish since {LastRequestReplenished}", isDebug);
108108
if (requestsToReplenish == 0 || RequestsUsed == 0)
109109
{
@@ -118,7 +118,7 @@ private void IncrementAvailableTokens(bool isDebug)
118118
}
119119

120120
// will try to decrement available tokens, will fail if another thread has used last of burst quota
121-
private bool TryDecrementAvailableTokens(bool isDebug)
121+
private bool TryIncrementRequestsUsed(bool isDebug)
122122
{
123123
var succeeded = false;
124124

Source/Tests/GlobalUsings.cs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
global using NUnit.Framework;

Source/Tests/RateLimitsTests.cs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using FikaAmazonAPI.Utils;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace Tests
10+
{
11+
[TestFixture]
12+
public class RateLimitsTests
13+
{
14+
[Test]
15+
[TestCase(0.1, 1, 3, 20000)]
16+
[TestCase(0.5, 1, 3, 4000)]
17+
[TestCase(1, 5, 10, 5000)]
18+
public async Task WaitForPermittedRequest_WaitsExpectedLengthOfTime(decimal rate, int burst, int numberRequests, int expectedWaitMilliseconds)
19+
{
20+
// Arrange
21+
var rateLimit = new RateLimits(rate, burst, RateLimitType.UNSET);
22+
23+
var stopwatch = new Stopwatch();
24+
var cancellationToken = new CancellationToken();
25+
26+
// Act
27+
stopwatch.Start();
28+
for (int i = 0; i < numberRequests; i++)
29+
{
30+
await rateLimit.WaitForPermittedRequest(cancellationToken, debugMode: true);
31+
}
32+
stopwatch.Stop();
33+
34+
// Assert
35+
Assert.That(stopwatch.ElapsedMilliseconds, Is.GreaterThanOrEqualTo(expectedWaitMilliseconds));
36+
// allow a second for additional time taken by the test to run
37+
Assert.That(stopwatch.ElapsedMilliseconds, Is.LessThanOrEqualTo(expectedWaitMilliseconds + 1000));
38+
}
39+
}
40+
}

Source/Tests/Tests.csproj

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
8+
<IsPackable>false</IsPackable>
9+
<IsTestProject>true</IsTestProject>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
14+
<PackageReference Include="NUnit" Version="3.13.3" />
15+
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
16+
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
17+
<PackageReference Include="coverlet.collector" Version="6.0.0" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\FikaAmazonAPI\FikaAmazonAPI.csproj" />
22+
</ItemGroup>
23+
24+
</Project>

0 commit comments

Comments
 (0)