Skip to content

Commit 77fc749

Browse files
committed
Run tests sequential
1 parent b8a8ec3 commit 77fc749

9 files changed

Lines changed: 117 additions & 35 deletions

File tree

src/OrchardCoreContrib.HealthChecks/Manifest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
)]
2424

2525
[assembly: Feature(
26-
Id = "OrchardCoreContrib.HealthCheck.RateLimiting",
26+
Id = "OrchardCoreContrib.HealthChecks.RateLimiting",
2727
Name = "Health Checks Rate Limiting",
2828
Description = "Limits requests to health check endpoints to prevent DOS attacks.",
2929
Dependencies = ["OrchardCoreContrib.HealthChecks"]
3030
)]
3131

3232
[assembly: Feature(
33-
Id = "OrchardCore.HealthCheck.BlockingRateLimiting",
33+
Id = "OrchardCoreContrib.HealthChecks.BlockingRateLimiting",
3434
Name = "Health Checks Blocking Rate Limiting",
3535
Description = "Adds blocking behavior to the health check rate limiter. Clients exceeding the limit are temporarily blocked to prevent DoS attacks.",
3636
Dependencies = new[] { "OrchardCoreContrib.HealthCheck.RateLimiting" }

src/OrchardCoreContrib.HealthChecks/Startup.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using OrchardCore.Environment.Shell.Configuration;
99
using OrchardCore.Modules;
1010
using OrchardCoreContrib.HealthChecks.Models;
11+
using OrchardCoreContrib.HealthChecks.Services;
1112
using System.Net.Mime;
1213
using System.Text.Json;
1314

@@ -83,19 +84,28 @@ public class RateLimitingStartup(IShellConfiguration shellConfiguration) : Start
8384
public override int Order => 30;
8485

8586
public override void ConfigureServices(IServiceCollection services)
86-
=> services.Configure<HealthChecksRateLimitingOptions>(shellConfiguration.GetSection($"{Constants.ConfigurationKey}:RateLimiting"));
87+
{
88+
services.Configure<HealthChecksRateLimitingOptions>(shellConfiguration.GetSection($"{Constants.ConfigurationKey}:RateLimiting"));
89+
90+
services.AddSingleton<IHealthCheckRateLimiter, HealthCheckRateLimiter>();
91+
}
8792

8893
public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
8994
=> app.UseMiddleware<HealthChecksRateLimitingMiddleware>();
9095
}
9196

9297
[Feature("OrchardCoreContrib.HealthChecks.BlockingRateLimiting")]
93-
public class HealthCheckBlockingRateLimitingStartup(IShellConfiguration shellConfiguration) : StartupBase
98+
public class BlockingRateLimitingStartup(IShellConfiguration shellConfiguration) : StartupBase
9499
{
95100
public override int Order => 20;
96101

97102
public override void ConfigureServices(IServiceCollection services)
98-
=> services.Configure<HealthChecksRateLimitingOptions>(shellConfiguration.GetSection($"{Constants.ConfigurationKey}:BlockingRateLimiting"));
103+
{
104+
var rateLimitingSection = shellConfiguration.GetSection($"{Constants.ConfigurationKey}:RateLimiting");
105+
106+
services.Configure<HealthChecksRateLimitingOptions>(rateLimitingSection);
107+
services.Configure<HealthChecksBlockingRateLimitingOptions>(rateLimitingSection);
108+
}
99109

100110
public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
101111
=> app.UseMiddleware<HealthChecksBlockingRateLimitingMiddleware>();

src/OrchardCoreContrib.Modules.Web/appsettings.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,11 @@
4747
"ShowDetails": true,
4848
"AllowedIPs": [ "127.0.0.1", "::1" ],
4949
"RateLimiting": {
50-
"PermitLimit": 5,
51-
"Window": "00:00:10",
52-
"SegmentsPerWindow": 10,
53-
"QueueLimit": 0
54-
},
55-
"BlockingRateLimiting": {
5650
"PermitLimit": 5,
5751
"Window": "00:00:10",
5852
"SegmentsPerWindow": 10,
5953
"QueueLimit": 0,
60-
"BlockDuration": "00:01:00"
54+
"BlockDuration": "00:00:10"
6155
}
6256
}
6357
//"OrchardCoreContrib_Garnet": {

test/OrchardCoreContrib.HealthChecks.Tests/HealthCheckBlockingTests.cs renamed to test/OrchardCoreContrib.HealthChecks.Tests/HealthCheckBlockingRateLimitingTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
namespace OrchardCoreContrib.HealthChecks.Tests;
55

6-
public class HealthCheckBlockingTests
6+
[Collection("Sequential")]
7+
public class HealthCheckBlockingRateLimitingTests
78
{
89
[Fact]
910
public async Task ExceedingLimit_ShouldBlockIP_ForConfiguredDuration()
@@ -57,7 +58,7 @@ public async Task BlockExpires_AfterDuration_AllowsRequestsAgain()
5758
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
5859

5960
// Wait slightly longer than block duration
60-
await Task.Delay(TimeSpan.FromSeconds(61));
61+
await Task.Delay(TimeSpan.FromSeconds(11));
6162

6263
response = await context.Client.GetAsync("health");
6364

test/OrchardCoreContrib.HealthChecks.Tests/HealthChecksIPRestrictionTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace OrchardCoreContrib.HealthChecks.Tests;
55

6+
[Collection("Sequential")]
67
public class HealthChecksIPRestrictionTests
78
{
89
[Theory]

test/OrchardCoreContrib.HealthChecks.Tests/HealthChecksMiddlewareOrderTests.cs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
using OrchardCoreContrib.HealthChecks.Tests.Tests;
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Http;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Options;
5+
using Moq;
6+
using OrchardCore.Environment.Shell.Configuration;
7+
using OrchardCoreContrib.HealthChecks.Services;
8+
using OrchardCoreContrib.HealthChecks.Tests.Tests;
29
using System.Net;
310

411
namespace OrchardCoreContrib.HealthChecks.Tests;
@@ -30,4 +37,71 @@ public async Task CorrectOrder_BlockedIp_ShouldReturn403_WithoutConsumingLimit()
3037
Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode);
3138
}
3239
}
40+
41+
[Fact]
42+
public void BlockingRateLimiting_ShouldRunBefore_RateLimiting()
43+
{
44+
// Arrange
45+
var shellConfiguration = Mock.Of<IShellConfiguration>();
46+
var blockingStartup = new BlockingRateLimitingStartup(shellConfiguration);
47+
var rateLimitingStartup = new RateLimitingStartup(shellConfiguration);
48+
49+
// Act
50+
var blockingOrder = blockingStartup.Order;
51+
var rateLimitingOrder = rateLimitingStartup.Order;
52+
53+
// Assert
54+
Assert.True(blockingOrder < rateLimitingOrder,
55+
$"BlockingRateLimiting order ({blockingOrder}) should be less than RateLimiting order ({rateLimitingOrder}).");
56+
}
57+
58+
//[Fact]
59+
//public async Task BlockingMiddleware_ShouldRunBefore_RateLimitingMiddleware()
60+
//{
61+
// var executed = new List<string>();
62+
63+
// var builder = WebApplication.CreateBuilder();
64+
// builder.Services.AddOptions<HealthChecksBlockingRateLimitingOptions>()
65+
// .Configure(o =>
66+
// {
67+
// o.PermitLimit = 1;
68+
// o.Window = TimeSpan.FromSeconds(5);
69+
// o.SegmentsPerWindow = 5;
70+
// o.BlockDuration = TimeSpan.FromSeconds(10);
71+
// });
72+
// builder.Services.AddSingleton<IHealthCheckRateLimiter, HealthCheckRateLimiter>();
73+
74+
// var app = builder.Build();
75+
76+
// // Register blocking first
77+
// app.Use(async (ctx, next) =>
78+
// {
79+
// executed.Add("Blocking");
80+
// //var middleware = new HealthChecksBlockingRateLimitingMiddleware(next,
81+
// // ctx.RequestServices.GetRequiredService<IOptions<HealthChecksBlockingRateLimitingOptions>>(),
82+
// // ctx.RequestServices.GetRequiredService<IClock>());
83+
// //await middleware.InvokeAsync(ctx);
84+
// });
85+
86+
// // Register plain limiter second
87+
// app.Use(async (ctx, next) =>
88+
// {
89+
// executed.Add("RateLimiting");
90+
// //var middleware = new HealthChecksRateLimitingMiddleware(next,
91+
// // ctx.RequestServices.GetRequiredService<IHealthCheckRateLimiter>());
92+
// //await middleware.InvokeAsync(ctx);
93+
// });
94+
95+
// app.Map("/health", () => Results.Ok("Healthy"));
96+
97+
// var client = app.CreateClient();
98+
// var response = await client.GetAsync("/health");
99+
100+
// // Assert pipeline order
101+
// Assert.Equal("Blocking", executed[0]);
102+
// Assert.Equal("RateLimiting", executed[1]);
103+
104+
// // Also assert response is OK for first request
105+
// Assert.Equal(HttpStatusCode.OK, response.StatusCode);
106+
//}
33107
}

test/OrchardCoreContrib.HealthChecks.Tests/HealthChecksRateLimitingTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace OrchardCoreContrib.HealthChecks.Tests;
55

6+
[Collection("Sequential")]
67
public class HealthChecksRateLimitingTests
78
{
89
[Fact]
Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<PropertyGroup>
4-
<ImplicitUsings>enable</ImplicitUsings>
5-
<IsPackable>false</IsPackable>
6-
<IsTestProject>true</IsTestProject>
7-
</PropertyGroup>
3+
<PropertyGroup>
4+
<ImplicitUsings>enable</ImplicitUsings>
5+
<IsPackable>false</IsPackable>
6+
<IsTestProject>true</IsTestProject>
7+
</PropertyGroup>
88

9-
<ItemGroup>
10-
<PackageReference Include="coverlet.collector" />
11-
<PackageReference Include="Microsoft.NET.Test.Sdk" />
12-
<PackageReference Include="OrchardCoreContrib.Testing" />
13-
<PackageReference Include="xunit" />
14-
<PackageReference Include="xunit.runner.visualstudio" />
15-
</ItemGroup>
9+
<ItemGroup>
10+
<PackageReference Include="coverlet.collector" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" />
12+
<PackageReference Include="Moq" />
13+
<PackageReference Include="OrchardCoreContrib.Testing" />
14+
<PackageReference Include="xunit" />
15+
<PackageReference Include="xunit.runner.visualstudio" />
16+
</ItemGroup>
1617

17-
<ItemGroup>
18-
<ProjectReference Include="..\..\src\OrchardCoreContrib.HealthChecks\OrchardCoreContrib.HealthChecks.csproj" />
19-
<ProjectReference Include="..\..\src\OrchardCoreContrib.Modules.Web\OrchardCoreContrib.Modules.Web.csproj" />
20-
</ItemGroup>
18+
<ItemGroup>
19+
<ProjectReference Include="..\..\src\OrchardCoreContrib.HealthChecks\OrchardCoreContrib.HealthChecks.csproj" />
20+
<ProjectReference Include="..\..\src\OrchardCoreContrib.Modules.Web\OrchardCoreContrib.Modules.Web.csproj" />
21+
</ItemGroup>
2122

22-
<ItemGroup>
23-
<Using Include="Xunit" />
24-
</ItemGroup>
23+
<ItemGroup>
24+
<Using Include="Xunit" />
25+
</ItemGroup>
2526

2627
</Project>

test/OrchardCoreContrib.HealthChecks.Tests/OrchardCoreStartup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public void ConfigureServices(IServiceCollection services)
1717
{
1818
services.AddOrchardCms(builder => builder
1919
.AddSetupFeatures("OrchardCore.Tenants")
20-
.AddTenantFeatures("OrchardCoreContrib.HealthChecks.IPRestriction", "OrchardCoreContrib.HealthChecks.RateLimiting", "OrchardCore.HealthCheck.BlockingRateLimiting")
20+
.AddTenantFeatures("OrchardCoreContrib.HealthChecks.IPRestriction", "OrchardCoreContrib.HealthChecks.RateLimiting", "OrchardCoreContrib.HealthChecks.BlockingRateLimiting")
2121
.ConfigureServices(serviceCollection =>
2222
{
2323
serviceCollection.AddScoped<IAuthorizationHandler, PermissionContextAuthorizationHandler>(sp =>

0 commit comments

Comments
 (0)