public async Task IfValidateAuthenticationStateAsyncReturnsUnrelatedCancelledTask_TreatAsFailure() { // Arrange var validationTcs = new TaskCompletionSource <bool>(); var authenticationStateChangedCount = 0; using var provider = new TestRevalidatingServerAuthenticationStateProvider( TimeSpan.FromMilliseconds(50)); provider.NextValidationResult = validationTcs.Task; provider.SetAuthenticationState(CreateAuthenticationStateTask("test user")); provider.AuthenticationStateChanged += _ => { authenticationStateChangedCount++; }; // Be waiting for the first ValidateAuthenticationStateAsync to complete await provider.NextValidateAuthenticationStateAsyncCall; var firstRevalidationCall = provider.RevalidationCallLog.Single(); Assert.Equal(0, authenticationStateChangedCount); // Act: ValidateAuthenticationStateAsync returns cancelled task, but the cancellation // is unrelated to the CT we supplied validationTcs.TrySetCanceled(new CancellationTokenSource().Token); // Assert: Since we didn't ask for that operation to be cancelled, this is treated as // a failure to validate, so we force a logout Assert.Equal(1, authenticationStateChangedCount); var newAuthState = await provider.GetAuthenticationStateAsync(); Assert.False(newAuthState.User.Identity.IsAuthenticated); Assert.Null(newAuthState.User.Identity.Name); }
public void AcceptsAndReturnsAuthStateFromHost() { // Arrange using var provider = new TestRevalidatingServerAuthenticationStateProvider(TimeSpan.MaxValue); // Act/Assert: Host can supply a value var hostAuthStateTask = (new TaskCompletionSource <AuthenticationState>()).Task; provider.SetAuthenticationState(hostAuthStateTask); Assert.Same(hostAuthStateTask, provider.GetAuthenticationStateAsync()); // Act/Assert: Host can supply a changed value var hostAuthStateTask2 = (new TaskCompletionSource <AuthenticationState>()).Task; provider.SetAuthenticationState(hostAuthStateTask2); Assert.Same(hostAuthStateTask2, provider.GetAuthenticationStateAsync()); }
public async Task IfValidateAuthenticationStateAsyncReturnsTrue_ContinuesRevalidating() { // Arrange using var provider = new TestRevalidatingServerAuthenticationStateProvider( TimeSpan.FromMilliseconds(50)); provider.SetAuthenticationState(CreateAuthenticationStateTask("test user")); provider.NextValidationResult = Task.FromResult(true); var didNotifyAuthenticationStateChanged = false; provider.AuthenticationStateChanged += _ => { didNotifyAuthenticationStateChanged = true; }; // Act for (var i = 0; i < 10; i++) { await provider.NextValidateAuthenticationStateAsyncCall; } // Assert Assert.Equal(10, provider.RevalidationCallLog.Count); Assert.False(didNotifyAuthenticationStateChanged); Assert.Equal("test user", (await provider.GetAuthenticationStateAsync()).User.Identity.Name); }
public async Task SuppliesCancellationTokenThatSignalsWhenRevalidationLoopIsBeingDiscarded() { // Arrange var validationTcs = new TaskCompletionSource <bool>(); var authenticationStateChangedCount = 0; using var provider = new TestRevalidatingServerAuthenticationStateProvider( TimeSpan.FromMilliseconds(50)); provider.NextValidationResult = validationTcs.Task; provider.SetAuthenticationState(CreateAuthenticationStateTask("test user")); provider.AuthenticationStateChanged += _ => { authenticationStateChangedCount++; }; // Act/Assert 1: token isn't cancelled initially await provider.NextValidateAuthenticationStateAsyncCall; var firstRevalidationCall = provider.RevalidationCallLog.Single(); Assert.False(firstRevalidationCall.CancellationToken.IsCancellationRequested); Assert.Equal(0, authenticationStateChangedCount); // Have the task throw a TCE to show this doesn't get treated as a failure firstRevalidationCall.CancellationToken.Register(() => validationTcs.TrySetCanceled(firstRevalidationCall.CancellationToken)); // Act/Assert 2: token is cancelled when the loop is superseded provider.NextValidationResult = Task.FromResult(true); provider.SetAuthenticationState(CreateAuthenticationStateTask("different user")); Assert.True(firstRevalidationCall.CancellationToken.IsCancellationRequested); // Since we asked for that operation to be cancelled, we don't treat it as a failure and // don't force a logout Assert.Equal(1, authenticationStateChangedCount); Assert.Equal("different user", (await provider.GetAuthenticationStateAsync()).User.Identity.Name); // Subsequent revalidation can complete successfully await provider.NextValidateAuthenticationStateAsyncCall; Assert.Collection(provider.RevalidationCallLog.Skip(1), call => Assert.Equal("different user", call.AuthenticationState.User.Identity.Name)); }