using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Autofac; using Volo.Abp.ExceptionHandling; using Volo.Abp.Modularity; namespace Volo.Abp.OperationRateLimiting; /// /// A mock store that simulates a concurrent race condition: /// - GetAsync always says the quota is available (Phase 1 checks pass). /// - IncrementAsync always says the quota is exhausted (Phase 2 finds another request consumed it). /// internal class RaceConditionSimulatorStore : IOperationRateLimitingStore { public Task GetAsync(string key, TimeSpan duration, int maxCount) { return Task.FromResult(new OperationRateLimitingStoreResult { IsAllowed = true, CurrentCount = 0, MaxCount = maxCount }); } public Task IncrementAsync(string key, TimeSpan duration, int maxCount) { // Simulate: between Phase 1 and Phase 2 another concurrent request consumed the last slot. return Task.FromResult(new OperationRateLimitingStoreResult { IsAllowed = false, CurrentCount = maxCount, MaxCount = maxCount, RetryAfter = duration }); } public Task ResetAsync(string key) { return Task.CompletedTask; } } [DependsOn( typeof(AbpOperationRateLimitingModule), typeof(AbpExceptionHandlingModule), typeof(AbpTestBaseModule), typeof(AbpAutofacModule) )] public class AbpOperationRateLimitingPhase2RaceTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.Replace( ServiceDescriptor.Transient()); Configure(options => { options.AddPolicy("TestRacePolicy", policy => { policy.WithFixedWindow(TimeSpan.FromHours(1), maxCount: 3) .PartitionByParameter(); }); }); } }