diff --git a/src/Middleware/OutputCaching/src/ISystemClock.cs b/src/Middleware/OutputCaching/src/ISystemClock.cs
deleted file mode 100644
index 8e2ead45b9d7..000000000000
--- a/src/Middleware/OutputCaching/src/ISystemClock.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.AspNetCore.OutputCaching;
-
-///
-/// Abstracts the system clock to facilitate testing.
-///
-internal interface ISystemClock
-{
- ///
- /// Retrieves the current system time in UTC.
- ///
- DateTimeOffset UtcNow { get; }
-}
diff --git a/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs b/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs
index 76b0bdb75e2d..15039d7c8815 100644
--- a/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs
+++ b/src/Middleware/OutputCaching/src/OutputCacheMiddleware.cs
@@ -243,7 +243,7 @@ internal async Task TryServeCachedResponseAsync(OutputCacheContext context
}
context.CachedResponse = cacheEntry;
- context.ResponseTime = _options.SystemClock.UtcNow;
+ context.ResponseTime = _options.TimeProvider.GetUtcNow();
var cacheEntryAge = context.ResponseTime.Value - context.CachedResponse.Created;
context.CachedEntryAge = cacheEntryAge > TimeSpan.Zero ? cacheEntryAge : TimeSpan.Zero;
@@ -464,7 +464,7 @@ private bool OnStartResponse(OutputCacheContext context)
if (!context.ResponseStarted)
{
context.ResponseStarted = true;
- context.ResponseTime = _options.SystemClock.UtcNow;
+ context.ResponseTime = _options.TimeProvider.GetUtcNow();
return true;
}
diff --git a/src/Middleware/OutputCaching/src/OutputCacheOptions.cs b/src/Middleware/OutputCaching/src/OutputCacheOptions.cs
index 709e6ff858a4..9e58a9c57401 100644
--- a/src/Middleware/OutputCaching/src/OutputCacheOptions.cs
+++ b/src/Middleware/OutputCaching/src/OutputCacheOptions.cs
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.ComponentModel;
-
namespace Microsoft.AspNetCore.OutputCaching;
///
@@ -45,8 +43,7 @@ public class OutputCacheOptions
///
/// For testing purposes only.
///
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal ISystemClock SystemClock { get; set; } = new SystemClock();
+ internal TimeProvider TimeProvider { get; set; } = TimeProvider.System;
///
/// Defines a which can be referenced by name.
diff --git a/src/Middleware/OutputCaching/src/SystemClock.cs b/src/Middleware/OutputCaching/src/SystemClock.cs
deleted file mode 100644
index 6cb33a828b8d..000000000000
--- a/src/Middleware/OutputCaching/src/SystemClock.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.AspNetCore.OutputCaching;
-
-///
-/// Provides access to the normal system clock.
-///
-internal sealed class SystemClock : ISystemClock
-{
- ///
- /// Retrieves the current system time in UTC.
- ///
- public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
-}
diff --git a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs
index 8b01426edf98..d2623feea6eb 100644
--- a/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs
+++ b/src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs
@@ -334,44 +334,38 @@ public void ContentIsNotModified_IfNoneMatch_MatchesAtLeastOneValue_True()
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new OutputCacheOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
context.ResponseTime = null;
middleware.StartResponse(context);
- Assert.Equal(clock.UtcNow, context.ResponseTime);
+ Assert.Equal(timeProvider.GetUtcNow(), context.ResponseTime);
}
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new OutputCacheOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
- var initialTime = clock.UtcNow;
+ var initialTime = timeProvider.GetUtcNow();
context.ResponseTime = null;
middleware.StartResponse(context);
Assert.Equal(initialTime, context.ResponseTime);
- clock.UtcNow += TimeSpan.FromSeconds(10);
+ timeProvider.Advance(TimeSpan.FromSeconds(10));
middleware.StartResponse(context);
- Assert.NotEqual(clock.UtcNow, context.ResponseTime);
+ Assert.NotEqual(timeProvider.GetUtcNow(), context.ResponseTime);
Assert.Equal(initialTime, context.ResponseTime);
}
@@ -393,20 +387,17 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_IgnoresExpiryIfAvailable(
{
// The Expires header should not be used when set in the response
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.MinValue
- };
+ var timeProvider = new TestTimeProvider(DateTimeOffset.MinValue);
var options = new OutputCacheOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
};
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: options);
var context = TestUtils.CreateTestContext();
- context.ResponseTime = clock.UtcNow;
- context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11));
+ context.ResponseTime = timeProvider.GetUtcNow();
+ context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
middleware.FinalizeCacheHeaders(context);
@@ -419,25 +410,22 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
{
// The MaxAge header should not be used if set in the response
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var sink = new TestSink();
var options = new OutputCacheOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
};
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: options);
var context = TestUtils.CreateTestContext();
- context.ResponseTime = clock.UtcNow;
+ context.ResponseTime = timeProvider.GetUtcNow();
context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(12)
}.ToString();
- context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11));
+ context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
middleware.FinalizeCacheHeaders(context);
@@ -448,25 +436,22 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var sink = new TestSink();
var options = new OutputCacheOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
};
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: options);
var context = TestUtils.CreateTestContext();
- context.ResponseTime = clock.UtcNow;
+ context.ResponseTime = timeProvider.GetUtcNow();
context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(12),
SharedMaxAge = TimeSpan.FromSeconds(13)
}.ToString();
- context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11));
+ context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
middleware.FinalizeCacheHeaders(context);
diff --git a/src/Middleware/OutputCaching/test/TestUtils.cs b/src/Middleware/OutputCaching/test/TestUtils.cs
index 51039bb81cd9..615cec55e535 100644
--- a/src/Middleware/OutputCaching/test/TestUtils.cs
+++ b/src/Middleware/OutputCaching/test/TestUtils.cs
@@ -146,7 +146,7 @@ private static IEnumerable CreateBuildersWithOutputCaching(
{
outputCachingOptions.MaximumBodySize = options.MaximumBodySize;
outputCachingOptions.UseCaseSensitivePaths = options.UseCaseSensitivePaths;
- outputCachingOptions.SystemClock = options.SystemClock;
+ outputCachingOptions.TimeProvider = options.TimeProvider;
outputCachingOptions.BasePolicies = options.BasePolicies;
outputCachingOptions.DefaultExpirationTimeSpan = options.DefaultExpirationTimeSpan;
outputCachingOptions.SizeLimit = options.SizeLimit;
@@ -347,9 +347,23 @@ public ValueTask SetAsync(string key, byte[] entry, string[]? tags, TimeSpan val
}
}
-internal class TestClock : ISystemClock
+internal class TestTimeProvider : TimeProvider
{
- public DateTimeOffset UtcNow { get; set; }
+ private DateTimeOffset _current;
+
+ public TestTimeProvider() : this(DateTimeOffset.UtcNow) { }
+
+ public TestTimeProvider(DateTimeOffset current)
+ {
+ _current = current;
+ }
+
+ public override DateTimeOffset GetUtcNow() => _current;
+
+ public void Advance(TimeSpan timeSpan)
+ {
+ _current += timeSpan;
+ }
}
internal class AllowTestPolicy : IOutputCachePolicy
diff --git a/src/Middleware/ResponseCaching/src/Interfaces/ISystemClock.cs b/src/Middleware/ResponseCaching/src/Interfaces/ISystemClock.cs
deleted file mode 100644
index 584b847e25e6..000000000000
--- a/src/Middleware/ResponseCaching/src/Interfaces/ISystemClock.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.AspNetCore.ResponseCaching;
-
-///
-/// Abstracts the system clock to facilitate testing.
-///
-internal interface ISystemClock
-{
- ///
- /// Retrieves the current system time in UTC.
- ///
- DateTimeOffset UtcNow { get; }
-}
diff --git a/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs b/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs
index eaaa433c9351..8131e512e7d3 100644
--- a/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs
+++ b/src/Middleware/ResponseCaching/src/ResponseCachingMiddleware.cs
@@ -142,7 +142,7 @@ internal async Task TryServeCachedResponseAsync(ResponseCachingContext con
context.CachedResponse = cachedResponse;
context.CachedResponseHeaders = cachedResponse.Headers;
- context.ResponseTime = _options.SystemClock.UtcNow;
+ context.ResponseTime = _options.TimeProvider.GetUtcNow();
var cachedEntryAge = context.ResponseTime.Value - context.CachedResponse.Created;
context.CachedEntryAge = cachedEntryAge > TimeSpan.Zero ? cachedEntryAge : TimeSpan.Zero;
@@ -374,7 +374,7 @@ private bool OnStartResponse(ResponseCachingContext context)
if (!context.ResponseStarted)
{
context.ResponseStarted = true;
- context.ResponseTime = _options.SystemClock.UtcNow;
+ context.ResponseTime = _options.TimeProvider.GetUtcNow();
return true;
}
diff --git a/src/Middleware/ResponseCaching/src/ResponseCachingOptions.cs b/src/Middleware/ResponseCaching/src/ResponseCachingOptions.cs
index 06917b322c35..cae036a28641 100644
--- a/src/Middleware/ResponseCaching/src/ResponseCachingOptions.cs
+++ b/src/Middleware/ResponseCaching/src/ResponseCachingOptions.cs
@@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.ComponentModel;
-
namespace Microsoft.AspNetCore.ResponseCaching;
///
@@ -31,6 +29,5 @@ public class ResponseCachingOptions
///
/// For testing purposes only.
///
- [EditorBrowsable(EditorBrowsableState.Never)]
- internal ISystemClock SystemClock { get; set; } = new SystemClock();
+ internal TimeProvider TimeProvider { get; set; } = TimeProvider.System;
}
diff --git a/src/Middleware/ResponseCaching/src/SystemClock.cs b/src/Middleware/ResponseCaching/src/SystemClock.cs
deleted file mode 100644
index 6fc3ad49cb0f..000000000000
--- a/src/Middleware/ResponseCaching/src/SystemClock.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.AspNetCore.ResponseCaching;
-
-///
-/// Provides access to the normal system clock.
-///
-internal sealed class SystemClock : ISystemClock
-{
- ///
- /// Retrieves the current system time in UTC.
- ///
- public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
-}
diff --git a/src/Middleware/ResponseCaching/test/ResponseCachingMiddlewareTests.cs b/src/Middleware/ResponseCaching/test/ResponseCachingMiddlewareTests.cs
index 4ef5f2b0ecad..212c77caf4fb 100644
--- a/src/Middleware/ResponseCaching/test/ResponseCachingMiddlewareTests.cs
+++ b/src/Middleware/ResponseCaching/test/ResponseCachingMiddlewareTests.cs
@@ -354,46 +354,40 @@ public void ContentIsNotModified_IfNoneMatch_MatchesAtLeastOneValue_True()
}
[Fact]
- public void StartResponsegAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
+ public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new ResponseCachingOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
context.ResponseTime = null;
middleware.StartResponse(context);
- Assert.Equal(clock.UtcNow, context.ResponseTime);
+ Assert.Equal(timeProvider.GetUtcNow(), context.ResponseTime);
}
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new ResponseCachingOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
- var initialTime = clock.UtcNow;
+ var initialTime = timeProvider.GetUtcNow();
context.ResponseTime = null;
middleware.StartResponse(context);
Assert.Equal(initialTime, context.ResponseTime);
- clock.UtcNow += TimeSpan.FromSeconds(10);
+ timeProvider.Advance(TimeSpan.FromSeconds(10));
middleware.StartResponse(context);
- Assert.NotEqual(clock.UtcNow, context.ResponseTime);
+ Assert.NotEqual(timeProvider.GetUtcNow(), context.ResponseTime);
Assert.Equal(initialTime, context.ResponseTime);
}
@@ -448,19 +442,16 @@ public void FinalizeCacheHeadersAsync_DefaultResponseValidity_Is10Seconds()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.MinValue
- };
+ var timeProvider = new TestTimeProvider(DateTimeOffset.MinValue);
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
- context.ResponseTime = clock.UtcNow;
- context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11));
+ context.ResponseTime = timeProvider.GetUtcNow();
+ context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
middleware.FinalizeCacheHeaders(context);
@@ -471,24 +462,21 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
- context.ResponseTime = clock.UtcNow;
+ context.ResponseTime = timeProvider.GetUtcNow();
context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(12)
}.ToString();
- context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11));
+ context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
middleware.FinalizeCacheHeaders(context);
@@ -499,24 +487,21 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable()
{
- var clock = new TestClock
- {
- UtcNow = DateTimeOffset.UtcNow
- };
+ var timeProvider = new TestTimeProvider();
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
{
- SystemClock = clock
+ TimeProvider = timeProvider
});
var context = TestUtils.CreateTestContext();
- context.ResponseTime = clock.UtcNow;
+ context.ResponseTime = timeProvider.GetUtcNow();
context.HttpContext.Response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(12),
SharedMaxAge = TimeSpan.FromSeconds(13)
}.ToString();
- context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(clock.UtcNow + TimeSpan.FromSeconds(11));
+ context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
middleware.FinalizeCacheHeaders(context);
diff --git a/src/Middleware/ResponseCaching/test/TestUtils.cs b/src/Middleware/ResponseCaching/test/TestUtils.cs
index 3a4b5584a759..14b5c211cb34 100644
--- a/src/Middleware/ResponseCaching/test/TestUtils.cs
+++ b/src/Middleware/ResponseCaching/test/TestUtils.cs
@@ -172,7 +172,7 @@ private static IEnumerable CreateBuildersWithResponseCaching(
{
responseCachingOptions.MaximumBodySize = options.MaximumBodySize;
responseCachingOptions.UseCaseSensitivePaths = options.UseCaseSensitivePaths;
- responseCachingOptions.SystemClock = options.SystemClock;
+ responseCachingOptions.TimeProvider = options.TimeProvider;
}
});
})
@@ -390,7 +390,21 @@ public void Set(string key, IResponseCacheEntry entry, TimeSpan validFor)
}
}
-internal class TestClock : ISystemClock
+internal class TestTimeProvider : TimeProvider
{
- public DateTimeOffset UtcNow { get; set; }
+ private DateTimeOffset _current;
+
+ public TestTimeProvider() : this(DateTimeOffset.UtcNow) { }
+
+ public TestTimeProvider(DateTimeOffset current)
+ {
+ _current = current;
+ }
+
+ public override DateTimeOffset GetUtcNow() => _current;
+
+ public void Advance(TimeSpan timeSpan)
+ {
+ _current += timeSpan;
+ }
}