Skip to content

Commit 3bbf321

Browse files
authored
Passes TimeProvider to date setting extensions (#184)
Ensures that the `TimeProvider` is passed to the `SetDates` and `SetCreatedDates` extension methods. This ensures that mocked time providers are correctly respected when setting the created and updated dates on entities, which is crucial for testing time-dependent logic. Adds tests to verify the correct behavior with mocked time providers, including future-dated scenarios.
1 parent 6886a10 commit 3bbf321

File tree

2 files changed

+60
-8
lines changed

2 files changed

+60
-8
lines changed

src/Foundatio.Repositories.Elasticsearch/Repositories/ElasticRepositoryBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,9 +1154,9 @@ protected virtual string GetTenantKey(IRepositoryQuery query)
11541154
private async Task OnDocumentsAddingAsync(IReadOnlyCollection<T> documents, ICommandOptions options)
11551155
{
11561156
if (HasDates)
1157-
documents.OfType<IHaveDates>().SetDates();
1157+
documents.OfType<IHaveDates>().SetDates(ElasticIndex.Configuration.TimeProvider);
11581158
else if (HasCreatedDate)
1159-
documents.OfType<IHaveCreatedDate>().SetCreatedDates();
1159+
documents.OfType<IHaveCreatedDate>().SetCreatedDates(ElasticIndex.Configuration.TimeProvider);
11601160

11611161
if (DocumentsAdding != null && DocumentsAdding.HasHandlers)
11621162
await DocumentsAdding.InvokeAsync(this, new DocumentsEventArgs<T>(documents, this, options)).AnyContext();
@@ -1186,7 +1186,7 @@ private async Task OnDocumentsSavingAsync(IReadOnlyCollection<T> documents, IRea
11861186
return;
11871187

11881188
if (HasDates)
1189-
documents.Cast<IHaveDates>().SetDates();
1189+
documents.Cast<IHaveDates>().SetDates(ElasticIndex.Configuration.TimeProvider);
11901190

11911191
documents.EnsureIds(ElasticIndex.CreateDocumentId, ElasticIndex.Configuration.TimeProvider);
11921192

tests/Foundatio.Repositories.Elasticsearch.Tests/RepositoryTests.cs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -642,26 +642,78 @@ public async Task SaveCollectionWithCachingAsync()
642642
}
643643

644644
[Fact]
645-
public async Task SetCreatedAndModifiedTimesAsync()
645+
public async Task AddAsync_WithMockedTimeProvider_ShouldSetExactTimes()
646646
{
647647
var timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMilliseconds(100)));
648648
_configuration.TimeProvider = timeProvider;
649649

650-
var nowUtc = timeProvider.GetUtcNow().UtcDateTime;
650+
var expectedTime = timeProvider.GetUtcNow().UtcDateTime;
651651
var employee = await _employeeRepository.AddAsync(EmployeeGenerator.Default);
652-
Assert.True(employee.CreatedUtc >= nowUtc);
653-
Assert.True(employee.UpdatedUtc >= nowUtc);
652+
653+
Assert.Equal(expectedTime, employee.CreatedUtc);
654+
Assert.Equal(expectedTime, employee.UpdatedUtc);
654655

655656
var createdUtc = employee.CreatedUtc;
656657
var updatedUtc = employee.UpdatedUtc;
657-
658658
employee.Name = Guid.NewGuid().ToString();
659659
timeProvider.Advance(TimeSpan.FromMilliseconds(100));
660+
var updatedExpectedTime = timeProvider.GetUtcNow().UtcDateTime;
661+
660662
employee = await _employeeRepository.SaveAsync(employee);
663+
661664
Assert.Equal(createdUtc, employee.CreatedUtc);
665+
Assert.Equal(updatedExpectedTime, employee.UpdatedUtc);
662666
Assert.True(updatedUtc < employee.UpdatedUtc, $"Previous UpdatedUtc: {updatedUtc} Current UpdatedUtc: {employee.UpdatedUtc}");
663667
}
664668

669+
[Fact]
670+
public async Task AddAsync_WithFutureMockedTimeProvider_ShouldRespectMockedTime()
671+
{
672+
// Arrange
673+
var futureTime = new DateTimeOffset(2030, 1, 15, 12, 0, 0, TimeSpan.Zero);
674+
var timeProvider = new FakeTimeProvider(futureTime);
675+
_configuration.TimeProvider = timeProvider;
676+
677+
// Act
678+
var expectedTime = timeProvider.GetUtcNow().UtcDateTime;
679+
var employee = await _employeeRepository.AddAsync(EmployeeGenerator.Default);
680+
681+
// Assert
682+
// These assertions will fail if SetDates/SetCreatedDates doesn't receive the TimeProvider
683+
// because the extension methods default to TimeProvider.System and will see the future
684+
// date as "in the future" and overwrite it with the real system time
685+
Assert.Equal(expectedTime, employee.CreatedUtc);
686+
Assert.Equal(expectedTime, employee.UpdatedUtc);
687+
}
688+
689+
[Fact]
690+
public async Task SaveAsync_WithFutureMockedTimeProvider_ShouldRespectMockedTime()
691+
{
692+
// Arrange
693+
var futureTime = new DateTimeOffset(2030, 1, 15, 12, 0, 0, TimeSpan.Zero);
694+
var timeProvider = new FakeTimeProvider(futureTime);
695+
_configuration.TimeProvider = timeProvider;
696+
697+
var expectedTime = timeProvider.GetUtcNow().UtcDateTime;
698+
var employee = await _employeeRepository.AddAsync(EmployeeGenerator.Default);
699+
700+
Assert.Equal(expectedTime, employee.CreatedUtc);
701+
Assert.Equal(expectedTime, employee.UpdatedUtc);
702+
703+
var createdUtc = employee.CreatedUtc;
704+
employee.Name = Guid.NewGuid().ToString();
705+
timeProvider.Advance(TimeSpan.FromHours(1));
706+
var updatedExpectedTime = timeProvider.GetUtcNow().UtcDateTime;
707+
708+
// Act
709+
employee = await _employeeRepository.SaveAsync(employee);
710+
711+
// Assert
712+
// CreatedUtc should remain unchanged, UpdatedUtc should reflect the advanced time
713+
Assert.Equal(createdUtc, employee.CreatedUtc);
714+
Assert.Equal(updatedExpectedTime, employee.UpdatedUtc);
715+
}
716+
665717
[Fact]
666718
public async Task CannotSetFutureCreatedAndModifiedTimesAsync()
667719
{

0 commit comments

Comments
 (0)