Skip to content

Commit

Permalink
Expose Epoch/start time from FakeTimeProvider
Browse files Browse the repository at this point in the history
It is often useful to have the epoch/start time available
via the FakeTimeProvider during testing, as it provides a
stable offset (time-0) from which to advance or set a new
utc-now based off, e.g. to move to time-X on a timeline
starting at time-0.
  • Loading branch information
egil committed Jun 6, 2023
1 parent 758ce3c commit ff5dd74
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Threading;

Expand All @@ -14,13 +15,22 @@ namespace Microsoft.Extensions.Time.Testing;
/// </summary>
public class FakeTimeProvider : TimeProvider
{
internal static readonly DateTimeOffset Epoch = new(2000, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);

internal readonly List<FakeTimeProviderTimer.Waiter> Waiters = new();

private DateTimeOffset _now = Epoch;
private DateTimeOffset _now;
private TimeZoneInfo _localTimeZone;

/// <summary>
/// Gets the time which was used as the starting point for the clock in this <see cref="FakeTimeProvider"/>.
/// </summary>
/// <remarks>
/// This can be set by passing in a <see cref="DateTimeOffset"/> to the constructor
/// which takes the <c>epoch</c> argument. If the default constructor is used,
/// the clocks start time defaults to midnight January 1st 2000.
/// </remarks>
[Experimental]
public DateTimeOffset Epoch { get; } = new DateTimeOffset(2000, 1, 1, 0, 0, 0, 0, TimeSpan.Zero);

/// <summary>
/// Initializes a new instance of the <see cref="FakeTimeProvider"/> class.
/// </summary>
Expand All @@ -31,16 +41,19 @@ public class FakeTimeProvider : TimeProvider
public FakeTimeProvider()
{
_localTimeZone = TimeZoneInfo.Utc;
_now = Epoch;
}

/// <summary>
/// Initializes a new instance of the <see cref="FakeTimeProvider"/> class.
/// </summary>
/// <param name="startTime">The initial time reported by the clock.</param>
public FakeTimeProvider(DateTimeOffset startTime)
/// <param name="epoch">The starting point for the clock used by this <see cref="FakeTimeProvider"/>.</param>
[Experimental]
public FakeTimeProvider(DateTimeOffset epoch)
: this()
{
_now = startTime;
Epoch = epoch;
_now = epoch;
}

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@ public void TriggerAndSchedule(bool restart)

if (_dueTimeMs == 0)
{
// If dueTime is zero, callback is invoked immediately
// If dueTime is zero, callback is invoked immediately.

_callback(_state);
}
else if (_dueTimeMs == Timeout.Infinite)
{
// If dueTime is Timeout.Infinite, callback is not invoked; the timer is disabled
// If dueTime is Timeout.Infinite, callback is not invoked; the timer is disabled.

return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<Workstream>Fundamentals</Workstream>
<Category>Testing</Category>
<PackageTags>$(PackageTags);Testing</PackageTags>
<InjectExperimentalAttributeOnLegacy>true</InjectExperimentalAttributeOnLegacy>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public void TryGetLogStream_WhenViewStreamDisposed_ReturnsFalse()
public async Task SelfDiagnosticsConfigRefresher_WhenConfigDisappearsAndAppearsBack_CaptureAsConfigured()
{
const string LogFileName = "withUnreliableConfig.log";
var timeProvider = new FakeTimeProvider(startTime: DateTime.UtcNow);
var timeProvider = new FakeTimeProvider(epoch: DateTime.UtcNow);
var parserMock = new Mock<SelfDiagnosticsConfigParser>();
var configFileContentInitial = @"{""LogDirectory"": ""."", ""FileSize"": 1024, ""LogLevel"": ""Verbose""}";
var configFileContentNew = @"{""LogDirectory"": ""."", ""FileSize"": 1025, ""LogLevel"": ""Verbose""}";
Expand Down Expand Up @@ -174,7 +174,7 @@ public async Task SelfDiagnosticsConfigRefresher_WhenConfigDisappearsAndAppearsB
public async Task SelfDiagnosticsConfigRefresher_WhenLogLevelUpdated_CaptureAsConfigured()
{
const string LogFileName = "withNewLogLevel.log";
var timeProvider = new FakeTimeProvider(startTime: DateTime.UtcNow);
var timeProvider = new FakeTimeProvider(epoch: DateTime.UtcNow);
var parserMock = new Mock<SelfDiagnosticsConfigParser>();
var configFileContentInitial = @"{""LogDirectory"": ""."", ""FileSize"": 1024, ""LogLevel"": ""Error""}";
var configFileContentNew = @"{""LogDirectory"": ""."", ""FileSize"": 1024, ""LogLevel"": ""Verbose""}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void DefaultCtor()
var timestamp = timeProvider.GetTimestamp();
var frequency = timeProvider.TimestampFrequency;

Assert.Equal(timeProvider.Epoch, now);
Assert.Equal(2000, now.Year);
Assert.Equal(1, now.Month);
Assert.Equal(1, now.Day);
Expand All @@ -34,6 +35,7 @@ public void DefaultCtor()
var frequency2 = timeProvider.TimestampFrequency;
var now2 = timeProvider.GetUtcNow();

Assert.Equal(timeProvider.Epoch, now2);
Assert.Equal(now, now2);
Assert.Equal(frequency, frequency2);
Assert.Equal(timestamp, timestamp2);
Expand All @@ -49,6 +51,7 @@ public void RichCtor()
var frequency = timeProvider.TimestampFrequency;
var now = timeProvider.GetUtcNow();

Assert.Equal(timeProvider.Epoch + TimeSpan.FromMilliseconds(8), now);
Assert.Equal(2001, now.Year);
Assert.Equal(2, now.Month);
Assert.Equal(3, now.Day);
Expand All @@ -64,6 +67,7 @@ public void RichCtor()
var frequency2 = timeProvider.TimestampFrequency;
now = timeProvider.GetUtcNow();

Assert.Equal(timeProvider.Epoch + TimeSpan.FromMilliseconds(16), now);
Assert.Equal(2001, now.Year);
Assert.Equal(2, now.Month);
Assert.Equal(3, now.Day);
Expand All @@ -72,7 +76,7 @@ public void RichCtor()
Assert.Equal(6, now.Second);
Assert.Equal(16, now.Millisecond);
Assert.Equal(frequency, frequency2);
Assert.True(pnow2 > pnow);
Assert.True(pnow2 > pnow);
}

[Fact]
Expand Down

0 comments on commit ff5dd74

Please sign in to comment.