Skip to content

Commit e2d421e

Browse files
committed
Fix rate limit errors for PackageLinkTests
1 parent ba3e715 commit e2d421e

File tree

1 file changed

+48
-6
lines changed

1 file changed

+48
-6
lines changed

StabilityMatrix.Tests/Models/Packages/PackageLinkTests.cs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
using System.Net.Http.Headers;
2+
using Polly;
3+
using Polly.Contrib.WaitAndRetry;
4+
using Polly.Retry;
25
using StabilityMatrix.Core.Models.Packages;
36

47
namespace StabilityMatrix.Tests.Models.Packages;
@@ -7,6 +10,7 @@ namespace StabilityMatrix.Tests.Models.Packages;
710
/// Tests that URL links on Packages should be valid. Requires internet connection.
811
/// </summary>
912
[TestClass]
13+
[TestCategory("Http")]
1014
public sealed class PackageLinkTests
1115
{
1216
private static HttpClient HttpClient { get; } =
@@ -15,14 +19,30 @@ public sealed class PackageLinkTests
1519
private static IEnumerable<object[]> PackagesData =>
1620
PackageHelper.GetPackages().Select(p => new object[] { p });
1721

22+
private static readonly AsyncRetryPolicy<HttpResponseMessage> RetryPolicy = Policy<HttpResponseMessage>
23+
.HandleResult(response => response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
24+
.WaitAndRetryAsync(
25+
Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromMilliseconds(200), 3),
26+
onRetry: (outcome, timespan, retryAttempt, context) =>
27+
{
28+
// Log retry attempt if needed
29+
Console.WriteLine($"Retry attempt {retryAttempt}, waiting {timespan.TotalSeconds} seconds");
30+
}
31+
);
32+
1833
[TestMethod]
1934
[DynamicData(nameof(PackagesData))]
2035
public async Task TestPreviewImageUri(BasePackage package)
2136
{
2237
var imageUri = package.PreviewImageUri;
2338

24-
// Test http head is successful
25-
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, imageUri));
39+
// If is GitHub Uri, use jsdelivr instead due to rate limiting
40+
imageUri = GitHubToJsDelivr(imageUri);
41+
42+
// Test http head is successful with retry policy
43+
var response = await RetryPolicy.ExecuteAsync(async () =>
44+
await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, imageUri))
45+
);
2646

2747
Assert.IsTrue(
2848
response.IsSuccessStatusCode,
@@ -38,13 +58,18 @@ public async Task TestLicenseUrl(BasePackage package)
3858
{
3959
if (string.IsNullOrEmpty(package.LicenseUrl))
4060
{
41-
Assert.Inconclusive();
61+
Assert.Inconclusive($"No LicenseUrl for package {package.GetType().Name} '{package.Name}'");
4262
}
4363

44-
var licenseUri = package.LicenseUrl;
64+
var licenseUri = new Uri(package.LicenseUrl);
65+
66+
// If is GitHub Uri, use jsdelivr instead due to rate limiting
67+
licenseUri = GitHubToJsDelivr(licenseUri);
4568

46-
// Test http head is successful
47-
var response = await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, licenseUri));
69+
// Test http head is successful with retry policy
70+
var response = await RetryPolicy.ExecuteAsync(async () =>
71+
await HttpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, licenseUri))
72+
);
4873

4974
Assert.IsTrue(
5075
response.IsSuccessStatusCode,
@@ -53,4 +78,21 @@ public async Task TestLicenseUrl(BasePackage package)
5378
response
5479
);
5580
}
81+
82+
private static Uri GitHubToJsDelivr(Uri uri)
83+
{
84+
// Like https://github.com/user/Repo/blob/main/LICENSE
85+
// becomes: https://cdn.jsdelivr.net/gh/user/Repo@main/LICENSE
86+
if (uri.Host.Equals("github.com", StringComparison.OrdinalIgnoreCase))
87+
{
88+
var segments = uri.AbsolutePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
89+
if (segments is [var user, var repo, "blob", var branch, ..])
90+
{
91+
var path = string.Join("/", segments.Skip(4));
92+
return new Uri($"https://cdn.jsdelivr.net/gh/{user}/{repo}@{branch}/{path}");
93+
}
94+
}
95+
96+
return uri;
97+
}
5698
}

0 commit comments

Comments
 (0)