Skip to content

Latest commit

 

History

History
537 lines (351 loc) · 40.3 KB

TimeProviderExtensions.ManualTimeProvider.md

File metadata and controls

537 lines (351 loc) · 40.3 KB

ManualTimeProvider Class

Represents a synthetic time provider that can be used to enable deterministic behavior in tests.

public class ManualTimeProvider

Inheritance System.TimeProvider 🡒 ManualTimeProvider

Remarks

Learn more at TimeProviderExtensions on GitHub.

Constructors

ManualTimeProvider() Constructor

Initializes a new instance of the ManualTimeProvider class.

public ManualTimeProvider();

Remarks

This creates a provider whose time is initially set to midnight January 1st 2000 and with the local time zone set to System.TimeZoneInfo.Utc. The provider is set to not automatically advance time each time it is read.

ManualTimeProvider(DateTimeOffset, TimeZoneInfo) Constructor

Initializes a new instance of the ManualTimeProvider class.

public ManualTimeProvider(System.DateTimeOffset startDateTime, System.TimeZoneInfo localTimeZone);

Parameters

startDateTime System.DateTimeOffset

The initial time and date reported by the provider.

localTimeZone System.TimeZoneInfo

Optional local time zone to use during testing. Defaults to System.TimeZoneInfo.Utc.

Remarks

The provider is set to not automatically advance time each time it is read.

ManualTimeProvider(DateTimeOffset) Constructor

Initializes a new instance of the ManualTimeProvider class.

public ManualTimeProvider(System.DateTimeOffset startDateTime);

Parameters

startDateTime System.DateTimeOffset

The initial time and date reported by the provider.

Remarks

The local time zone set to System.TimeZoneInfo.Utc. The provider is set to not automatically advance time each time it is read.

Properties

ManualTimeProvider.ActiveTimers Property

Gets the number of active ManualTimer, that have callbacks that are scheduled to be triggered at some point in the future.

public int ActiveTimers { get; }

Property Value

System.Int32

ManualTimeProvider.AutoAdvanceBehavior Property

Gets or sets the auto advance behavior of this ManualTimeProvider.

public TimeProviderExtensions.AutoAdvanceBehavior AutoAdvanceBehavior { get; set; }

Property Value

AutoAdvanceBehavior

ManualTimeProvider.Start Property

Gets the starting date and time for this provider.

public System.DateTimeOffset Start { get; set; }

Property Value

System.DateTimeOffset

ManualTimeProvider.TimestampFrequency Property

Gets the amount by which the value from GetTimestamp() increments per second.

public override long TimestampFrequency { get; }

Property Value

System.Int64

Remarks

This is fixed to the value of System.TimeSpan.TicksPerSecond.

Methods

ManualTimeProvider.Advance(TimeSpan) Method

Advances time by a specific amount.

public void Advance(System.TimeSpan delta);

Parameters

delta System.TimeSpan

The amount of time to advance the clock by.

Exceptions

System.ArgumentOutOfRangeException
Thrown if delta is negative. Going back in time is not supported.

Remarks

Advancing time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.

If advancing time moves it paste multiple scheduled timer callbacks, the current date/time reported by GetUtcNow() at the point when each callback is invoked will match the due time of the callback.

For example:

var start = sut.GetTimestamp();

var timer = manualTimeProvider.CreateTimer(
                callback: _ => manualTimeProvider.GetElapsedTime(start),
                state: null,
                dueTime: Span.FromSecond(1),
                period: TimeSpan.FromSecond(1));

manualTimeProvider.Advance(TimeSpan.FromSecond(3));

The call to Advance(TimeSpan.FromSecond(3)) causes the timers callback to be invoked three times, and the result of the manualTimeProvider.GetElapsedTime(start) in the callback call will be 1 second, 2 seconds, and 3 seconds. In other words, the time of the provider is set before the time callback is invoked to the time that the callback is scheduled to be invoked at.

If the desired result is to jump time by delta and then invoke the timer callbacks the expected number of times, i.e. such that the result of manualTimeProvider.GetElapsedTime(start) in the callback is 3 seconds, 3 seconds, and 3 seconds, use Jump(DateTimeOffset) or Jump(TimeSpan) instead.

Learn more about this behavior at in the documentation.

ManualTimeProvider.CreateManualTimer(TimerCallback, object, ManualTimeProvider) Method

Creates an instance of a ManualTimer. This method is called by CreateTimer(TimerCallback, object, TimeSpan, TimeSpan).

protected internal virtual TimeProviderExtensions.ManualTimer CreateManualTimer(System.Threading.TimerCallback callback, object? state, TimeProviderExtensions.ManualTimeProvider timeProvider);

Parameters

callback System.Threading.TimerCallback

A delegate representing a method to be executed when the timer fires. The method specified for callback should be reentrant, as it may be invoked simultaneously on two threads if the timer fires again before or while a previous callback is still being handled.

state System.Object

An object to be passed to the callback. This may be null.

timeProvider ManualTimeProvider

The ManualTimeProvider which is used to schedule invocations of the callback with.

Returns

ManualTimer

Remarks

Override this methods to return a custom implementation of ManualTimer. This also allows for intercepting and wrapping the provided timer callback and state, enabling more advanced testing scenarios.

ManualTimeProvider.CreateTimer(TimerCallback, object, TimeSpan, TimeSpan) Method

Creates a new System.Threading.ITimer instance, using System.TimeSpan values to measure time intervals.

public TimeProviderExtensions.ManualTimer CreateTimer(System.Threading.TimerCallback callback, object? state, System.TimeSpan dueTime, System.TimeSpan period);

Parameters

callback System.Threading.TimerCallback

A delegate representing a method to be executed when the timer fires. The method specified for callback should be reentrant, as it may be invoked simultaneously on two threads if the timer fires again before or while a previous callback is still being handled.

state System.Object

An object to be passed to the callback. This may be null.

dueTime System.TimeSpan

The amount of time to delay before callback is invoked. Specify System.Threading.Timeout.InfiniteTimeSpan to prevent the timer from starting. Specify System.TimeSpan.Zero to start the timer immediately.

period System.TimeSpan

The time interval between invocations of callback. Specify System.Threading.Timeout.InfiniteTimeSpan to disable periodic signaling.

Returns

ManualTimer
The newly created System.Threading.ITimer instance.

Exceptions

System.ArgumentNullException
callback is null.

System.ArgumentOutOfRangeException
The number of milliseconds in the value of dueTime or period is negative and not equal to System.Threading.Timeout.Infinite, or is greater than System.Int32.MaxValue.

Remarks

The delegate specified by the callback parameter is invoked once after dueTime elapses, and thereafter each time the period time interval elapses.

If dueTime is zero, the callback is invoked immediately. If dueTime is -1 milliseconds, callback is not invoked; the timer is disabled, but can be re-enabled by calling the System.Threading.ITimer.Change(System.TimeSpan,System.TimeSpan) method.

If period is 0 or -1 milliseconds and dueTime is positive, callback is invoked once; the periodic behavior of the timer is disabled, but can be re-enabled using the System.Threading.ITimer.Change(System.TimeSpan,System.TimeSpan) method.

The return System.Threading.ITimer instance will be implicitly rooted while the timer is still scheduled.

CreateTimer(TimerCallback, object, TimeSpan, TimeSpan) captures the System.Threading.ExecutionContext and stores that with the System.Threading.ITimer for use in invoking callback each time it's called. That capture can be suppressed with System.Threading.ExecutionContext.SuppressFlow.

To move time forward for the returned System.Threading.ITimer, call Advance(TimeSpan) or SetUtcNow(DateTimeOffset) on this time provider.

ManualTimeProvider.GetTimestamp() Method

Gets the current high-frequency value designed to measure small time intervals with high accuracy in the timer mechanism.

public override long GetTimestamp();

Returns

System.Int64
A long integer representing the high-frequency counter value of the underlying timer mechanism.

Remarks

This implementation bases timestamp on System.DateTimeOffset.UtcTicks, since the progression of time is represented by the date and time returned from GetUtcNow().

If TimestampAdvanceAmount is greater than System.TimeSpan.Zero, calling this method will move time forward by the amount specified by TimestampAdvanceAmount. The long returned from this method will reflect the timestamp before the auto advance was applied, if any.

ManualTimeProvider.GetUtcNow() Method

Gets a System.DateTimeOffset value whose date and time are set to the current Coordinated Universal Time (UTC) date and time and whose offset is Zero, all according to this ManualTimeProvider's notion of time.

public override System.DateTimeOffset GetUtcNow();

Returns

System.DateTimeOffset

Remarks

If UtcNowAdvanceAmount is greater than System.TimeSpan.Zero, calling this method will move time forward by the amount specified by UtcNowAdvanceAmount. The System.DateTimeOffset returned from this method will reflect the time before the auto advance was applied, if any.

ManualTimeProvider.Jump(DateTimeOffset) Method

Jumps the date and time returned by GetUtcNow() to value and triggers any scheduled items that are waiting for time to be forwarded.

public void Jump(System.DateTimeOffset value);

Parameters

value System.DateTimeOffset

The new UtcNow time.

Exceptions

System.ArgumentOutOfRangeException
Thrown if value is less than the value returned by GetUtcNow(). Going back in time is not supported.

Remarks

Jumping time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.

If jumping time moves it paste one or more scheduled timer callbacks, the current date/time reported by GetUtcNow() and GetTimestamp() will match the new date/time based on the value specified in the request.

For example:

var start = sut.GetTimestamp();

var timer = manualTimeProvider.CreateTimer(
                callback: _ => manualTimeProvider.GetElapsedTime(start),
                state: null,
                dueTime: Span.FromSecond(1),
                period: TimeSpan.FromSecond(1));

manualTimeProvider.Jump(manualTimeProvider.Start + TimeSpan.FromSecond(3));

The call to Jump(manualTimeProvider.Start + TimeSpan.FromSecond(3)) causes the timers callback to be invoked three times, and the result of the manualTimeProvider.GetElapsedTime(start) in the callback call will be 3 seconds during all three invocations.

If the desired result is that timer callbacks happens exactly at their scheduled callback time, i.e. such that the result of manualTimeProvider.GetElapsedTime(start) in the callback will be 1 second, 2 seconds, and 3 seconds, use Advance(TimeSpan) or SetUtcNow(DateTimeOffset) instead.

Learn more about this behavior at in the documentation. ///

ManualTimeProvider.Jump(TimeSpan) Method

Jumps time by a specific amount.

public void Jump(System.TimeSpan delta);

Parameters

delta System.TimeSpan

The amount of time to jump the clock by.

Exceptions

System.ArgumentOutOfRangeException
Thrown if delta is negative. Going back in time is not supported.

Remarks

Jumping time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.

If jumping time moves it paste one or more scheduled timer callbacks, the current date/time reported by GetUtcNow() and GetTimestamp() will match the new date/time based on the delta specified in the request.

For example:

var start = sut.GetTimestamp();

var timer = manualTimeProvider.CreateTimer(
                callback: _ => manualTimeProvider.GetElapsedTime(start),
                state: null,
                dueTime: Span.FromSecond(1),
                period: TimeSpan.FromSecond(1));

manualTimeProvider.Jump(TimeSpan.FromSecond(3));

The call to Jump(TimeSpan.FromSecond(3)) causes the timers callback to be invoked three times, and the result of the manualTimeProvider.GetElapsedTime(start) in the callback call will be 3 seconds during all three invocations.

If the desired result is that timer callbacks happens exactly at their scheduled callback time, i.e. such that the result of manualTimeProvider.GetElapsedTime(start) in the callback will be 1 second, 2 seconds, and 3 seconds, use Advance(TimeSpan) or SetUtcNow(DateTimeOffset) instead.

Learn more about this behavior at in the documentation. ///

ManualTimeProvider.SetLocalTimeZone(TimeZoneInfo) Method

Sets the local time zone.

public void SetLocalTimeZone(System.TimeZoneInfo localTimeZone);

Parameters

localTimeZone System.TimeZoneInfo

The local time zone.

ManualTimeProvider.SetUtcNow(DateTimeOffset) Method

Sets the date and time returned by GetUtcNow() to value and triggers any scheduled items that are waiting for time to be forwarded.

public void SetUtcNow(System.DateTimeOffset value);

Parameters

value System.DateTimeOffset

The new UtcNow time.

Exceptions

System.ArgumentOutOfRangeException
Thrown if value is less than the value returned by GetUtcNow(). Going back in time is not supported.

Remarks

Setting time affects the timers created from this provider, and all other operations that are directly or indirectly using this provider as a time source. Whereas when using System.TimeProvider.System, time marches forward automatically in hardware, for the manual time provider the application is responsible for doing this explicitly by calling this method.

If the set time moves it paste multiple scheduled timer callbacks, the current date/time reported by GetUtcNow() at the point when each callback is invoked will match the due time of the callback.

For example:

var start = sut.GetTimestamp();

var timer = manualTimeProvider.CreateTimer(
                callback: _ => manualTimeProvider.GetElapsedTime(start),
                state: null,
                dueTime: Span.FromSecond(1),
                period: TimeSpan.FromSecond(1));

manualTimeProvider.SetUtcNow(manualTimeProvider.Start + TimeSpan.FromSecond(3));

The call to SetUtcNow(manualTimeProvider.Start + TimeSpan.FromSecond(3)) causes the timers callback to be invoked three times, and the result of the manualTimeProvider.GetElapsedTime(start) in the callback call will be 1 second, 2 seconds, and 3 seconds. In other words, the time of the provider is set before the time callback is invoked to the time that the callback is scheduled to be invoked at.

If the desired result is to jump to the time specified in value and then invoke the timer callbacks the expected number of times, i.e. such that the result of manualTimeProvider.GetElapsedTime(start) in the callback is 3 seconds, 3 seconds, and 3 seconds, use Jump(DateTimeOffset) or Jump(TimeSpan) instead.

Learn more about this behavior at in the documentation. ///

ManualTimeProvider.ToString() Method

Returns a string representation this clock's current time.

public override string ToString();

Returns

System.String
A string representing the clock's current time.