[Microsoft.Extensions.TimeProvider.Testing] FakeTimeProvider does not simulate timers correctly, misses executions
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 894
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 23
Description
### Description
I am working with a non-periodic Timer that re-schedules itself with the `ITimer.Change` method. I noticed that `FakeTimeProvider.Advance` only ever executes the timer once, even if I provide a `TimeSpan` that covers multiple executions.
### Reproduction Steps
```csharp
public class TimerBugRepro
{
[Fact]
public void TestWithSystemTime() // Works
{
Assert.Equal(2, RunTestWithTimeProvider(TimeProvider.System, () => Thread.Sleep(TimeSpan.FromSeconds(3))));
}
[Fact]
public void TestWithFakeTime() // Fails
{
var fakeTime = new FakeTimeProvider();
Assert.Equal(2, RunTestWithTimeProvider(fakeTime, () => fakeTime.Advance(TimeSpan.FromSeconds(3))));
}
private int RunTestWithTimeProvider(TimeProvider timeProvider, Action sleepAction)
{
int count = 0;
ITimer timer = null;
timer = timeProvider.CreateTimer(
_ =>
{
Interlocked.Increment(ref count);
timer.Change(TimeSpan.FromSeconds(2), Timeout.InfiniteTimeSpan);
},
null,
Timeout.InfiniteTimeSpan,
Timeout.InfiniteTimeSpan);
timer.Change(TimeSpan.FromMilliseconds(1), Timeout.InfiniteTimeSpan); // Both tests work for TimeSpan.Zero
sleepAction();
return count;
}
}
```
### Expected behavior
The `FakeTimeProvider.Advance` should correctly simulate the behavior for `TimeProvider.System` + `Thread.Sleep`.
### Actual behavior
The Fake-Timer does not get re-sheduled correctly.
### Regression?
_No response_
### Known Workarounds
_No response_
### Configuration
.NET SDK version: 9.0.100
TargetFramework: net8.0
Microsoft.Extensions.TimeProvider.Testing version: 9.0.0
OS: Windows 10 10.0.19045
### Other information
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.