public async Task SendAsync_ShouldRaise_SessionExpired_WhenRefreshFailed() { // Arrange _tokenClient.RefreshTokenAsync(Arg.Any <CancellationToken>()) .Returns(ApiResponseResult <RefreshTokenResponse> .Fail(HttpStatusCode.BadRequest, "Refresh failed")); var handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage) { InnerHandler = _innerHandler }; var client = new HttpClient(handler) { BaseAddress = _baseAddress }; _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(HttpStatusCode.Unauthorized); using (var monitoredSubject = handler.Monitor()) { // Act var request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); await client.SendAsync(request); // Assert monitoredSubject.Should().Raise(nameof(UnauthorizedResponseHandler.SessionExpired)); _innerHandler.VerifyNoOutstandingExpectation(); } }
public async Task SendAsync_ShouldBe_InnerHandlerSendAsync() { // Arrange var handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage) { InnerHandler = _innerHandler }; var client = new HttpClient(handler) { BaseAddress = _baseAddress }; var response = new HttpResponseMessage(HttpStatusCode.OK); _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(req => response); var request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); // Act var result = await client.SendAsync(request); // Assert result.Should().BeSameAs(response); _innerHandler.VerifyNoOutstandingExpectation(); }
public async Task SendAsync_ShouldSet_TokenStorage_Tokens() { // Arrange _tokenClient.RefreshTokenAsync(Arg.Any <CancellationToken>()) .Returns(ApiResponseResult <RefreshTokenResponse> .Ok( new RefreshTokenResponse { AccessToken = "New access token", RefreshToken = "New refresh token" })); var handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage) { InnerHandler = _innerHandler }; var client = new HttpClient(handler) { BaseAddress = _baseAddress }; _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(HttpStatusCode.Unauthorized); // Act var request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); await client.SendAsync(request); // Assert _tokenStorage.AccessToken.Should().Be("New access token"); _tokenStorage.RefreshToken.Should().Be("New refresh token"); }
public async Task SendAsync_ShouldRepeatRequest_WithRefreshedAccessToken() { // Arrange _tokenClient.RefreshTokenAsync(Arg.Any <CancellationToken>()) .Returns(ApiResponseResult <RefreshTokenResponse> .Ok( new RefreshTokenResponse { AccessToken = "New access token", RefreshToken = "New refresh token" })); var handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage) { InnerHandler = _innerHandler }; var client = new HttpClient(handler) { BaseAddress = _baseAddress }; _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(HttpStatusCode.Unauthorized); _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .WithHeaders("Authorization", "Bearer New access token") .Respond(HttpStatusCode.OK); // Act var request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); await client.SendAsync(request); // Assert _innerHandler.VerifyNoOutstandingExpectation(); }
public async Task SendAsync_ShouldBe_InnerHandlerSendAsync_WhenRepeatedRequest() { // Arrange UnauthorizedResponseHandler handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage, _logger) { InnerHandler = _innerHandler }; HttpClient client = new HttpClient(handler) { BaseAddress = _baseAddress }; HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(HttpStatusCode.Unauthorized); _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(req => response); // Act HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); HttpResponseMessage result = await client.SendAsync(request); // Assert result.Should().BeSameAs(response); }
public async Task SendAsync_ShouldNotCall_TokenClient_RefreshTokenAsync_WhenTokenClientRefreshTokenAsyncThrowsArgumentNullException() { // Arrange string exceptionMessage = "The RefreshToken in RefreshTokenData can't be null."; ArgumentNullException exception = new ArgumentNullException(exceptionMessage); _tokenClient.RefreshTokenAsync(Arg.Any <CancellationToken>()) .Throws(exception); UnauthorizedResponseHandler handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage, _logger) { InnerHandler = _innerHandler }; HttpClient client = new HttpClient(handler) { BaseAddress = _baseAddress }; _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(HttpStatusCode.Unauthorized); // Act HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); await client.SendAsync(request); // Assert await _tokenClient.Received(1).RefreshTokenAsync(Arg.Any <CancellationToken>()); _logger.Received(1).Error($"An error occurred when refreshing the auth token: {exceptionMessage}"); }
public async Task SendAsync_ShouldCall_TokenClient_RefreshTokenAsync_WhenUnauthorized() { // Arrange var handler = new UnauthorizedResponseHandler(_tokenClient, _tokenStorage, _userStorage) { InnerHandler = _innerHandler }; var client = new HttpClient(handler) { BaseAddress = _baseAddress }; _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/logicals") .Respond(HttpStatusCode.Unauthorized); // Act var request = new HttpRequestMessage(HttpMethod.Get, "/logicals"); await client.SendAsync(request); // Assert await _tokenClient.Received(1).RefreshTokenAsync(Arg.Any <CancellationToken>()); }
public async Task SendAsync_ShouldRetryWithNewToken_WhenRefreshedWhileRequesting() { // Arrange var breakpointHandler = new BreakpointHandler { InnerHandler = _innerHandler }; var requestBreakpoint = breakpointHandler.Breakpoint; var breakpointTokenClient = new BreakpointTokenClient(_tokenClient); var tokenClientBreakpoint = breakpointTokenClient.Breakpoint; var handler = new UnauthorizedResponseHandler(breakpointTokenClient, _tokenStorage, _userStorage) { InnerHandler = breakpointHandler }; var client = new HttpClient(handler) { BaseAddress = _baseAddress }; _tokenClient.RefreshTokenAsync(Arg.Any <CancellationToken>()) .Returns(ApiResponseResult <RefreshTokenResponse> .Ok( new RefreshTokenResponse { AccessToken = "New access token", RefreshToken = "New refresh token" })); var response = new HttpResponseMessage(HttpStatusCode.OK); // Act var task1 = Task.CompletedTask; var task2 = Task.CompletedTask; try { // Sending first request and pausing it var request1 = new HttpRequestMessage(HttpMethod.Get, "/vpn"); task1 = client.SendAsync(request1); var request1Hit = await requestBreakpoint.WaitForHit().TimeoutAfter(TestTimeout); // Sending second request and pausing it var request2 = new HttpRequestMessage(HttpMethod.Get, "/profiles"); task2 = client.SendAsync(request2); var request2Hit = await requestBreakpoint.WaitForHit().TimeoutAfter(TestTimeout); // Continue first request and get Unauthorized _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/vpn") .Respond(HttpStatusCode.Unauthorized); request1Hit.Continue(); // First request initiated token refresh await tokenClientBreakpoint.WaitForHitAndContinue().TimeoutAfter(TestTimeout); // First request retried with new tokens request1Hit = await requestBreakpoint.WaitForHit().TimeoutAfter(TestTimeout); _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/vpn") .WithHeaders("Authorization", "Bearer New access token") .Respond(req => response); request1Hit.Continue(); await task1.TimeoutAfter(TestTimeout); // Second request continues and gets Unauthorized _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/profiles") .Respond(HttpStatusCode.Unauthorized); request2Hit.Continue(); // Second request retried with new access token request2Hit = await requestBreakpoint.WaitForHit().TimeoutAfter(TestTimeout); _innerHandler.Expect(HttpMethod.Get, "https://api.protonvpn.ch/profiles") .WithHeaders("Authorization", "Bearer New access token") .Respond(req => response); request2Hit.Continue(); } finally { await task1.TimeoutAfter(TestTimeout); await task2.TimeoutAfter(TestTimeout); } // Assert await _tokenClient.Received(1).RefreshTokenAsync(Arg.Any <CancellationToken>()); _innerHandler.VerifyNoOutstandingExpectation(); }