Files
ColaFlow/colaflow-api/tests/Modules/Identity/ColaFlow.Modules.Identity.Domain.Tests/Entities/EmailRateLimitTests.cs
Yaojia Wang 172d0de1fe
Some checks failed
Code Coverage / Generate Coverage Report (push) Has been cancelled
Tests / Run Tests (9.0.x) (push) Has been cancelled
Tests / Docker Build Test (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Add test
2025-11-04 00:20:42 +01:00

177 lines
5.0 KiB
C#

using ColaFlow.Modules.Identity.Domain.Entities;
using FluentAssertions;
using Xunit;
namespace ColaFlow.Modules.Identity.Domain.Tests.Entities;
public sealed class EmailRateLimitTests
{
private readonly Guid _tenantId = Guid.NewGuid();
private const string TestEmail = "user@example.com";
private const string OperationType = "verification";
[Fact]
public void Create_WithValidData_ShouldSucceed()
{
// Arrange & Act
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
// Assert
rateLimit.Should().NotBeNull();
rateLimit.Id.Should().NotBe(Guid.Empty);
rateLimit.Email.Should().Be(TestEmail.ToLower());
rateLimit.TenantId.Should().Be(_tenantId);
rateLimit.OperationType.Should().Be(OperationType);
rateLimit.AttemptsCount.Should().Be(1);
rateLimit.LastSentAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
}
[Fact]
public void Create_ShouldNormalizeEmail()
{
// Arrange
const string mixedCaseEmail = "User@EXAMPLE.COM";
// Act
var rateLimit = EmailRateLimit.Create(mixedCaseEmail, _tenantId, OperationType);
// Assert
rateLimit.Email.Should().Be("user@example.com");
}
[Fact]
public void Create_WithEmptyEmail_ShouldThrowException()
{
// Arrange & Act
var act = () => EmailRateLimit.Create(string.Empty, _tenantId, OperationType);
// Assert
act.Should().Throw<ArgumentException>()
.WithMessage("*Email cannot be empty*");
}
[Fact]
public void Create_WithEmptyOperationType_ShouldThrowException()
{
// Arrange & Act
var act = () => EmailRateLimit.Create(TestEmail, _tenantId, string.Empty);
// Assert
act.Should().Throw<ArgumentException>()
.WithMessage("*Operation type cannot be empty*");
}
[Fact]
public void RecordAttempt_ShouldIncrementCount()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
var initialCount = rateLimit.AttemptsCount;
var initialLastSentAt = rateLimit.LastSentAt;
// Wait a bit to ensure time difference
System.Threading.Thread.Sleep(10);
// Act
rateLimit.RecordAttempt();
// Assert
rateLimit.AttemptsCount.Should().Be(initialCount + 1);
rateLimit.LastSentAt.Should().BeAfter(initialLastSentAt);
}
[Fact]
public void RecordAttempt_MultipleCallsMultiple_ShouldIncrementCorrectly()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
// Act
rateLimit.RecordAttempt();
rateLimit.RecordAttempt();
rateLimit.RecordAttempt();
// Assert
rateLimit.AttemptsCount.Should().Be(4); // 1 initial + 3 increments
}
[Fact]
public void ResetAttempts_ShouldResetCountToOne()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
rateLimit.RecordAttempt();
rateLimit.RecordAttempt();
rateLimit.RecordAttempt();
// Act
rateLimit.ResetAttempts();
// Assert
rateLimit.AttemptsCount.Should().Be(1);
}
[Fact]
public void ResetAttempts_ShouldUpdateLastSentAt()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
var initialLastSentAt = rateLimit.LastSentAt;
// Wait a bit to ensure time difference
System.Threading.Thread.Sleep(10);
// Act
rateLimit.ResetAttempts();
// Assert
rateLimit.LastSentAt.Should().BeAfter(initialLastSentAt);
rateLimit.LastSentAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
}
[Fact]
public void IsWindowExpired_WithinWindow_ShouldReturnFalse()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
var window = TimeSpan.FromMinutes(5);
// Act
var isExpired = rateLimit.IsWindowExpired(window);
// Assert
isExpired.Should().BeFalse();
}
[Fact]
public void IsWindowExpired_OutsideWindow_ShouldReturnTrue()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
var window = TimeSpan.FromMilliseconds(1);
// Wait for window to expire
System.Threading.Thread.Sleep(10);
// Act
var isExpired = rateLimit.IsWindowExpired(window);
// Assert
isExpired.Should().BeTrue();
}
[Fact]
public void IsWindowExpired_WithZeroWindow_ShouldReturnTrue()
{
// Arrange
var rateLimit = EmailRateLimit.Create(TestEmail, _tenantId, OperationType);
var window = TimeSpan.Zero;
// Act
var isExpired = rateLimit.IsWindowExpired(window);
// Assert
isExpired.Should().BeTrue();
}
}