Skip to content

Commit 7c89649

Browse files
authored
Replace ISystemClock with TimeProvider in Kestrel, unify mock TimeProviders (#48081)
1 parent 078041f commit 7c89649

File tree

100 files changed

+844
-1013
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+844
-1013
lines changed

src/Identity/test/Identity.FunctionalTests/MapIdentityTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public async Task CanLoginWithBearerToken(string addIdentityMode)
7070
[Fact]
7171
public async Task CanCustomizeBearerTokenExpiration()
7272
{
73-
var clock = new TestTimeProvider();
73+
var clock = new MockTimeProvider();
7474
var expireTimeSpan = TimeSpan.FromSeconds(42);
7575

7676
await using var app = await CreateAppAsync(services =>

src/Identity/test/Identity.FunctionalTests/Microsoft.AspNetCore.Identity.FunctionalTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<Compile Include="..\..\UI\src\UIFramework.cs" Link="Infrastructure\UIFramework.cs" />
1111
<Compile Include="$(SharedSourceRoot)ThrowHelpers\ArgumentNullThrowHelper.cs" LinkBase="Shared" />
1212
<Compile Include="$(SharedSourceRoot)CallerArgument\CallerArgumentExpressionAttribute.cs" LinkBase="Shared" />
13-
<Compile Include="$(IdentityTestSharedSourceRoot)\TestTimeProvider.cs" LinkBase="Shared" />
13+
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
1414

1515
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
1616
</ItemGroup>

src/Identity/test/Identity.Test/Microsoft.AspNetCore.Identity.Test.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
</PropertyGroup>
66

77
<ItemGroup>
8-
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" />
8+
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" LinkBase="Shared" />
9+
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
910
</ItemGroup>
1011

1112
<ItemGroup>

src/Identity/test/Identity.Test/SecurityStampValidatorTest.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Microsoft.AspNetCore.Authentication;
66
using Microsoft.AspNetCore.Authentication.Cookies;
77
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Testing;
89
using Microsoft.Extensions.DependencyInjection;
910
using Microsoft.Extensions.Logging;
1011
using Microsoft.Extensions.Options;
@@ -270,7 +271,7 @@ public async Task OnValidateIdentityDoesNotRejectsWhenNotExpired()
270271
public async Task OnValidateIdentityDoesNotExtendExpirationWhenSlidingIsDisabled()
271272
{
272273
var user = new PocoUser("test");
273-
var timeProvider = new TestTimeProvider(new DateTimeOffset(2013, 6, 11, 12, 34, 56, 0, TimeSpan.Zero));
274+
var timeProvider = new MockTimeProvider();
274275
var httpContext = new Mock<HttpContext>();
275276
var userManager = MockHelpers.MockUserManager<PocoUser>();
276277
var identityOptions = new Mock<IOptions<IdentityOptions>>();
@@ -308,8 +309,10 @@ public async Task OnValidateIdentityDoesNotExtendExpirationWhenSlidingIsDisabled
308309
await SecurityStampValidator.ValidatePrincipalAsync(context);
309310

310311
// Issued is moved forward, expires is not.
311-
Assert.Equal(timeProvider.GetUtcNow(), context.Properties.IssuedUtc);
312-
Assert.Equal(timeProvider.GetUtcNow() + TimeSpan.FromDays(1), context.Properties.ExpiresUtc);
312+
var now = timeProvider.GetUtcNow();
313+
now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Offset); // Truncate to the nearest second.
314+
Assert.Equal(now, context.Properties.IssuedUtc);
315+
Assert.Equal(now + TimeSpan.FromDays(1), context.Properties.ExpiresUtc);
313316
Assert.NotNull(context.Principal);
314317
}
315318

src/Identity/test/InMemory.Test/FunctionalTest.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.AspNetCore.Http;
1515
using Microsoft.AspNetCore.Identity.Test;
1616
using Microsoft.AspNetCore.TestHost;
17+
using Microsoft.AspNetCore.Testing;
1718
using Microsoft.Extensions.DependencyInjection;
1819
using Microsoft.Extensions.Hosting;
1920
using Microsoft.Net.Http.Headers;
@@ -66,7 +67,7 @@ public async Task CookieContainsRoleClaim()
6667
[InlineData(false)]
6768
public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration(bool testCore)
6869
{
69-
var timeProvider = new TestTimeProvider();
70+
var timeProvider = new MockTimeProvider();
7071
var server = await CreateServer(services =>
7172
{
7273
services.ConfigureApplicationCookie(options =>
@@ -114,10 +115,10 @@ public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration(bool test
114115
[InlineData(false, false)]
115116
public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe, bool testCore)
116117
{
117-
var timeProvider = new TestTimeProvider();
118+
var timeProvider = new MockTimeProvider();
118119
var server = await CreateServer(services =>
119120
{
120-
services.Configure<SecurityStampValidatorOptions>(o => o.TimeProvider = timeProvider);
121+
services.AddSingleton<TimeProvider>(timeProvider);
121122
}, testCore: testCore);
122123

123124
var transaction1 = await SendAsync(server, "http://example.com/createMe");
@@ -163,12 +164,12 @@ public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool remembe
163164
[InlineData(false)]
164165
public async Task CanAccessOldPrincipalDuringSecurityStampReplacement(bool testCore)
165166
{
166-
var timeProvider = new TestTimeProvider();
167+
var timeProvider = new MockTimeProvider();
167168
var server = await CreateServer(services =>
168169
{
170+
services.AddSingleton<TimeProvider>(timeProvider);
169171
services.Configure<SecurityStampValidatorOptions>(options =>
170172
{
171-
options.TimeProvider = timeProvider;
172173
options.OnRefreshingPrincipal = c =>
173174
{
174175
var newId = new ClaimsIdentity();
@@ -216,7 +217,7 @@ public async Task CanAccessOldPrincipalDuringSecurityStampReplacement(bool testC
216217
[InlineData(false)]
217218
public async Task TwoFactorRememberCookieVerification(bool testCore)
218219
{
219-
var timeProvider = new TestTimeProvider();
220+
var timeProvider = new MockTimeProvider();
220221
var server = await CreateServer(services => services.AddSingleton<TimeProvider>(timeProvider), testCore: testCore);
221222

222223
var transaction1 = await SendAsync(server, "http://example.com/createMe");
@@ -245,7 +246,7 @@ public async Task TwoFactorRememberCookieVerification(bool testCore)
245246
[InlineData(false)]
246247
public async Task TwoFactorRememberCookieClearedBySecurityStampChange(bool testCore)
247248
{
248-
var timeProvider = new TestTimeProvider();
249+
var timeProvider = new MockTimeProvider();
249250
var server = await CreateServer(services => services.AddSingleton<TimeProvider>(timeProvider), testCore: testCore);
250251

251252
var transaction1 = await SendAsync(server, "http://example.com/createMe");

src/Identity/test/InMemory.Test/Microsoft.AspNetCore.Identity.InMemory.Test.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
</PropertyGroup>
66

77
<ItemGroup>
8-
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" />
8+
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" LinkBase="Shared" />
9+
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
910
</ItemGroup>
1011

1112
<ItemGroup>
@@ -18,3 +19,4 @@
1819
</ItemGroup>
1920

2021
</Project>
22+

src/Identity/test/Shared/TestTimeProvider.cs

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/Middleware/OutputCaching/test/Microsoft.AspNetCore.OutputCaching.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
</Content>
1111
</ItemGroup>
1212

13+
<ItemGroup>
14+
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
15+
</ItemGroup>
16+
1317
<ItemGroup>
1418
<Reference Include="Microsoft.AspNetCore.OutputCaching" />
1519
<Reference Include="Microsoft.AspNetCore.TestHost" />

src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.AspNetCore.Http;
88
using Microsoft.AspNetCore.Http.Features;
99
using Microsoft.AspNetCore.OutputCaching.Memory;
10+
using Microsoft.AspNetCore.Testing;
1011
using Microsoft.Extensions.Caching.Memory;
1112
using Microsoft.Extensions.Logging.Testing;
1213
using Microsoft.Extensions.Primitives;
@@ -334,7 +335,7 @@ public void ContentIsNotModified_IfNoneMatch_MatchesAtLeastOneValue_True()
334335
[Fact]
335336
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
336337
{
337-
var timeProvider = new TestTimeProvider();
338+
var timeProvider = new MockTimeProvider();
338339
var middleware = TestUtils.CreateTestMiddleware(options: new OutputCacheOptions
339340
{
340341
TimeProvider = timeProvider
@@ -350,7 +351,7 @@ public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
350351
[Fact]
351352
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
352353
{
353-
var timeProvider = new TestTimeProvider();
354+
var timeProvider = new MockTimeProvider();
354355
var middleware = TestUtils.CreateTestMiddleware(options: new OutputCacheOptions
355356
{
356357
TimeProvider = timeProvider
@@ -387,7 +388,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_IgnoresExpiryIfAvailable(
387388
{
388389
// The Expires header should not be used when set in the response
389390

390-
var timeProvider = new TestTimeProvider(DateTimeOffset.MinValue);
391+
var timeProvider = new MockTimeProvider();
391392
var options = new OutputCacheOptions
392393
{
393394
TimeProvider = timeProvider
@@ -410,7 +411,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
410411
{
411412
// The MaxAge header should not be used if set in the response
412413

413-
var timeProvider = new TestTimeProvider();
414+
var timeProvider = new MockTimeProvider();
414415
var sink = new TestSink();
415416
var options = new OutputCacheOptions
416417
{
@@ -436,7 +437,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
436437
[Fact]
437438
public void FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable()
438439
{
439-
var timeProvider = new TestTimeProvider();
440+
var timeProvider = new MockTimeProvider();
440441
var sink = new TestSink();
441442
var options = new OutputCacheOptions
442443
{

src/Middleware/OutputCaching/test/TestUtils.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,25 +347,6 @@ public ValueTask SetAsync(string key, byte[] entry, string[]? tags, TimeSpan val
347347
}
348348
}
349349

350-
internal class TestTimeProvider : TimeProvider
351-
{
352-
private DateTimeOffset _current;
353-
354-
public TestTimeProvider() : this(DateTimeOffset.UtcNow) { }
355-
356-
public TestTimeProvider(DateTimeOffset current)
357-
{
358-
_current = current;
359-
}
360-
361-
public override DateTimeOffset GetUtcNow() => _current;
362-
363-
public void Advance(TimeSpan timeSpan)
364-
{
365-
_current += timeSpan;
366-
}
367-
}
368-
369350
internal class AllowTestPolicy : IOutputCachePolicy
370351
{
371352
public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellationToken)

src/Middleware/ResponseCaching/test/Microsoft.AspNetCore.ResponseCaching.Tests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
</Content>
1111
</ItemGroup>
1212

13+
<ItemGroup>
14+
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
15+
</ItemGroup>
16+
1317
<ItemGroup>
1418
<Reference Include="Microsoft.AspNetCore.ResponseCaching" />
1519
<Reference Include="Microsoft.AspNetCore.TestHost" />

src/Middleware/ResponseCaching/test/ResponseCachingMiddlewareTests.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using Microsoft.AspNetCore.Http;
55
using Microsoft.AspNetCore.Http.Features;
6+
using Microsoft.AspNetCore.Testing;
67
using Microsoft.Extensions.Caching.Memory;
78
using Microsoft.Extensions.Logging.Testing;
89
using Microsoft.Extensions.Primitives;
@@ -356,7 +357,7 @@ public void ContentIsNotModified_IfNoneMatch_MatchesAtLeastOneValue_True()
356357
[Fact]
357358
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
358359
{
359-
var timeProvider = new TestTimeProvider();
360+
var timeProvider = new MockTimeProvider();
360361
var middleware = TestUtils.CreateTestMiddleware(options: new ResponseCachingOptions
361362
{
362363
TimeProvider = timeProvider
@@ -372,7 +373,7 @@ public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
372373
[Fact]
373374
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
374375
{
375-
var timeProvider = new TestTimeProvider();
376+
var timeProvider = new MockTimeProvider();
376377
var middleware = TestUtils.CreateTestMiddleware(options: new ResponseCachingOptions
377378
{
378379
TimeProvider = timeProvider
@@ -442,7 +443,10 @@ public void FinalizeCacheHeadersAsync_DefaultResponseValidity_Is10Seconds()
442443
[Fact]
443444
public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
444445
{
445-
var timeProvider = new TestTimeProvider(DateTimeOffset.MinValue);
446+
var timeProvider = new MockTimeProvider();
447+
var now = timeProvider.GetUtcNow();
448+
now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second + 1, now.Offset); // Round up to seconds.
449+
timeProvider.AdvanceTo(now);
446450
var sink = new TestSink();
447451
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
448452
{
@@ -451,7 +455,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
451455
var context = TestUtils.CreateTestContext();
452456

453457
context.ResponseTime = timeProvider.GetUtcNow();
454-
context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(timeProvider.GetUtcNow() + TimeSpan.FromSeconds(11));
458+
context.HttpContext.Response.Headers.Expires = HeaderUtilities.FormatDate(now + TimeSpan.FromSeconds(11));
455459

456460
middleware.FinalizeCacheHeaders(context);
457461

@@ -462,7 +466,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
462466
[Fact]
463467
public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
464468
{
465-
var timeProvider = new TestTimeProvider();
469+
var timeProvider = new MockTimeProvider();
466470
var sink = new TestSink();
467471
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
468472
{
@@ -487,7 +491,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
487491
[Fact]
488492
public void FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable()
489493
{
490-
var timeProvider = new TestTimeProvider();
494+
var timeProvider = new MockTimeProvider();
491495
var sink = new TestSink();
492496
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
493497
{

src/Middleware/ResponseCaching/test/TestUtils.cs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -389,22 +389,3 @@ public void Set(string key, IResponseCacheEntry entry, TimeSpan validFor)
389389
_storage[key] = entry;
390390
}
391391
}
392-
393-
internal class TestTimeProvider : TimeProvider
394-
{
395-
private DateTimeOffset _current;
396-
397-
public TestTimeProvider() : this(DateTimeOffset.UtcNow) { }
398-
399-
public TestTimeProvider(DateTimeOffset current)
400-
{
401-
_current = current;
402-
}
403-
404-
public override DateTimeOffset GetUtcNow() => _current;
405-
406-
public void Advance(TimeSpan timeSpan)
407-
{
408-
_current += timeSpan;
409-
}
410-
}

src/Security/Authentication/test/CertificateTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,8 @@ public async Task VerifyValidationResultNeverCachedAfter30Min(bool cache)
688688
{
689689
const string Expected = "John Doe";
690690
var validationCount = 0;
691-
var timeProvider = new TestTimeProvider();
691+
// The test certs are generated based off UtcNow.
692+
var timeProvider = new MockTimeProvider(TimeProvider.System.GetUtcNow());
692693

693694
using var host = await CreateHost(
694695
new CertificateAuthenticationOptions

src/Security/Authentication/test/CookieTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies;
2121

2222
public class CookieTests : SharedAuthenticationTests<CookieAuthenticationOptions>
2323
{
24-
private readonly TestTimeProvider _timeProvider = new();
24+
private readonly MockTimeProvider _timeProvider = new();
2525

2626
protected override string DefaultScheme => CookieAuthenticationDefaults.AuthenticationScheme;
2727
protected override Type HandlerType => typeof(CookieAuthenticationHandler);

src/Security/Authentication/test/Microsoft.AspNetCore.Authentication.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
<ItemGroup>
1616
<Compile Include="$(SharedSourceRoot)test\Certificates\Certificates.cs" />
17+
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" />
1718

1819
<Content Include="WsFederation\federationmetadata.xml">
1920
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

src/Security/Authentication/test/SharedAuthenticationTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
using System.Security.Claims;
55
using Microsoft.AspNetCore.Authentication.Tests;
66
using Microsoft.AspNetCore.Http;
7+
using Microsoft.AspNetCore.Testing;
78
using Microsoft.Extensions.DependencyInjection;
89

910
namespace Microsoft.AspNetCore.Authentication;
1011

1112
public abstract class SharedAuthenticationTests<TOptions> where TOptions : AuthenticationSchemeOptions
1213
{
13-
protected TestTimeProvider TimeProvider { get; } = new();
14+
protected MockTimeProvider TimeProvider { get; } = new();
1415

1516
protected abstract string DefaultScheme { get; }
1617
protected virtual string DisplayName { get; }

0 commit comments

Comments
 (0)