Skip to content

Commit

Permalink
Replace ISystemClock with TimeProvider in Kestrel, unify mock TimePro…
Browse files Browse the repository at this point in the history
…viders (dotnet#48081)
  • Loading branch information
Tratcher authored May 19, 2023
1 parent 078041f commit 7c89649
Show file tree
Hide file tree
Showing 100 changed files with 844 additions and 1,013 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public async Task CanLoginWithBearerToken(string addIdentityMode)
[Fact]
public async Task CanCustomizeBearerTokenExpiration()
{
var clock = new TestTimeProvider();
var clock = new MockTimeProvider();
var expireTimeSpan = TimeSpan.FromSeconds(42);

await using var app = await CreateAppAsync(services =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<Compile Include="..\..\UI\src\UIFramework.cs" Link="Infrastructure\UIFramework.cs" />
<Compile Include="$(SharedSourceRoot)ThrowHelpers\ArgumentNullThrowHelper.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)CallerArgument\CallerArgumentExpressionAttribute.cs" LinkBase="Shared" />
<Compile Include="$(IdentityTestSharedSourceRoot)\TestTimeProvider.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />

<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" />
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
</ItemGroup>

<ItemGroup>
Expand Down
9 changes: 6 additions & 3 deletions src/Identity/test/Identity.Test/SecurityStampValidatorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand Down Expand Up @@ -270,7 +271,7 @@ public async Task OnValidateIdentityDoesNotRejectsWhenNotExpired()
public async Task OnValidateIdentityDoesNotExtendExpirationWhenSlidingIsDisabled()
{
var user = new PocoUser("test");
var timeProvider = new TestTimeProvider(new DateTimeOffset(2013, 6, 11, 12, 34, 56, 0, TimeSpan.Zero));
var timeProvider = new MockTimeProvider();
var httpContext = new Mock<HttpContext>();
var userManager = MockHelpers.MockUserManager<PocoUser>();
var identityOptions = new Mock<IOptions<IdentityOptions>>();
Expand Down Expand Up @@ -308,8 +309,10 @@ public async Task OnValidateIdentityDoesNotExtendExpirationWhenSlidingIsDisabled
await SecurityStampValidator.ValidatePrincipalAsync(context);

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

Expand Down
15 changes: 8 additions & 7 deletions src/Identity/test/InMemory.Test/FunctionalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Net.Http.Headers;
Expand Down Expand Up @@ -66,7 +67,7 @@ public async Task CookieContainsRoleClaim()
[InlineData(false)]
public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration(bool testCore)
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var server = await CreateServer(services =>
{
services.ConfigureApplicationCookie(options =>
Expand Down Expand Up @@ -114,10 +115,10 @@ public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration(bool test
[InlineData(false, false)]
public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe, bool testCore)
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var server = await CreateServer(services =>
{
services.Configure<SecurityStampValidatorOptions>(o => o.TimeProvider = timeProvider);
services.AddSingleton<TimeProvider>(timeProvider);
}, testCore: testCore);

var transaction1 = await SendAsync(server, "http://example.com/createMe");
Expand Down Expand Up @@ -163,12 +164,12 @@ public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool remembe
[InlineData(false)]
public async Task CanAccessOldPrincipalDuringSecurityStampReplacement(bool testCore)
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var server = await CreateServer(services =>
{
services.AddSingleton<TimeProvider>(timeProvider);
services.Configure<SecurityStampValidatorOptions>(options =>
{
options.TimeProvider = timeProvider;
options.OnRefreshingPrincipal = c =>
{
var newId = new ClaimsIdentity();
Expand Down Expand Up @@ -216,7 +217,7 @@ public async Task CanAccessOldPrincipalDuringSecurityStampReplacement(bool testC
[InlineData(false)]
public async Task TwoFactorRememberCookieVerification(bool testCore)
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var server = await CreateServer(services => services.AddSingleton<TimeProvider>(timeProvider), testCore: testCore);

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

var transaction1 = await SendAsync(server, "http://example.com/createMe");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" />
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
</ItemGroup>

<ItemGroup>
Expand All @@ -18,3 +19,4 @@
</ItemGroup>

</Project>

23 changes: 0 additions & 23 deletions src/Identity/test/Shared/TestTimeProvider.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
</Content>
</ItemGroup>

<ItemGroup>
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
</ItemGroup>

<ItemGroup>
<Reference Include="Microsoft.AspNetCore.OutputCaching" />
<Reference Include="Microsoft.AspNetCore.TestHost" />
Expand Down
11 changes: 6 additions & 5 deletions src/Middleware/OutputCaching/test/OutputCacheMiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.OutputCaching.Memory;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Primitives;
Expand Down Expand Up @@ -334,7 +335,7 @@ public void ContentIsNotModified_IfNoneMatch_MatchesAtLeastOneValue_True()
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new OutputCacheOptions
{
TimeProvider = timeProvider
Expand All @@ -350,7 +351,7 @@ public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new OutputCacheOptions
{
TimeProvider = timeProvider
Expand Down Expand Up @@ -387,7 +388,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_IgnoresExpiryIfAvailable(
{
// The Expires header should not be used when set in the response

var timeProvider = new TestTimeProvider(DateTimeOffset.MinValue);
var timeProvider = new MockTimeProvider();
var options = new OutputCacheOptions
{
TimeProvider = timeProvider
Expand All @@ -410,7 +411,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
{
// The MaxAge header should not be used if set in the response

var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var sink = new TestSink();
var options = new OutputCacheOptions
{
Expand All @@ -436,7 +437,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var sink = new TestSink();
var options = new OutputCacheOptions
{
Expand Down
19 changes: 0 additions & 19 deletions src/Middleware/OutputCaching/test/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,25 +347,6 @@ public ValueTask SetAsync(string key, byte[] entry, string[]? tags, TimeSpan val
}
}

internal class TestTimeProvider : TimeProvider
{
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
{
public ValueTask CacheRequestAsync(OutputCacheContext context, CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
</Content>
</ItemGroup>

<ItemGroup>
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" LinkBase="Shared" />
</ItemGroup>

<ItemGroup>
<Reference Include="Microsoft.AspNetCore.ResponseCaching" />
<Reference Include="Microsoft.AspNetCore.TestHost" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Primitives;
Expand Down Expand Up @@ -356,7 +357,7 @@ public void ContentIsNotModified_IfNoneMatch_MatchesAtLeastOneValue_True()
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new ResponseCachingOptions
{
TimeProvider = timeProvider
Expand All @@ -372,7 +373,7 @@ public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTime()
[Fact]
public void StartResponseAsync_IfAllowResponseCaptureIsTrue_SetsResponseTimeOnlyOnce()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var middleware = TestUtils.CreateTestMiddleware(options: new ResponseCachingOptions
{
TimeProvider = timeProvider
Expand Down Expand Up @@ -442,7 +443,10 @@ public void FinalizeCacheHeadersAsync_DefaultResponseValidity_Is10Seconds()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
{
var timeProvider = new TestTimeProvider(DateTimeOffset.MinValue);
var timeProvider = new MockTimeProvider();
var now = timeProvider.GetUtcNow();
now = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second + 1, now.Offset); // Round up to seconds.
timeProvider.AdvanceTo(now);
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
{
Expand All @@ -451,7 +455,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
var context = TestUtils.CreateTestContext();

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

middleware.FinalizeCacheHeaders(context);

Expand All @@ -462,7 +466,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseExpiryIfAvailable()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
{
Expand All @@ -487,7 +491,7 @@ public void FinalizeCacheHeadersAsync_ResponseValidity_UseMaxAgeIfAvailable()
[Fact]
public void FinalizeCacheHeadersAsync_ResponseValidity_UseSharedMaxAgeIfAvailable()
{
var timeProvider = new TestTimeProvider();
var timeProvider = new MockTimeProvider();
var sink = new TestSink();
var middleware = TestUtils.CreateTestMiddleware(testSink: sink, options: new ResponseCachingOptions
{
Expand Down
19 changes: 0 additions & 19 deletions src/Middleware/ResponseCaching/test/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -389,22 +389,3 @@ public void Set(string key, IResponseCacheEntry entry, TimeSpan validFor)
_storage[key] = entry;
}
}

internal class TestTimeProvider : TimeProvider
{
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;
}
}
3 changes: 2 additions & 1 deletion src/Security/Authentication/test/CertificateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,8 @@ public async Task VerifyValidationResultNeverCachedAfter30Min(bool cache)
{
const string Expected = "John Doe";
var validationCount = 0;
var timeProvider = new TestTimeProvider();
// The test certs are generated based off UtcNow.
var timeProvider = new MockTimeProvider(TimeProvider.System.GetUtcNow());

using var host = await CreateHost(
new CertificateAuthenticationOptions
Expand Down
2 changes: 1 addition & 1 deletion src/Security/Authentication/test/CookieTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Authentication.Cookies;

public class CookieTests : SharedAuthenticationTests<CookieAuthenticationOptions>
{
private readonly TestTimeProvider _timeProvider = new();
private readonly MockTimeProvider _timeProvider = new();

protected override string DefaultScheme => CookieAuthenticationDefaults.AuthenticationScheme;
protected override Type HandlerType => typeof(CookieAuthenticationHandler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

<ItemGroup>
<Compile Include="$(SharedSourceRoot)test\Certificates\Certificates.cs" />
<Compile Include="$(SharedSourceRoot)test\MockTimeProvider.cs" />

<Content Include="WsFederation\federationmetadata.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.Tests;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Authentication;

public abstract class SharedAuthenticationTests<TOptions> where TOptions : AuthenticationSchemeOptions
{
protected TestTimeProvider TimeProvider { get; } = new();
protected MockTimeProvider TimeProvider { get; } = new();

protected abstract string DefaultScheme { get; }
protected virtual string DisplayName { get; }
Expand Down
Loading

0 comments on commit 7c89649

Please sign in to comment.