From 7c078d9c62f9f0fca2487164b8e9aa6a29215e59 Mon Sep 17 00:00:00 2001 From: Peter Wasonga Ombwa Date: Wed, 20 Feb 2019 09:52:21 -0800 Subject: [PATCH 1/5] Version Bump, Fix Newtonsoft Reference --- .../Microsoft.Graph.Core.csproj | 10 +++++----- .../Properties/AssemblyInfo.cs | 4 ++-- src/Microsoft.Graph/Microsoft.Graph.csproj | 16 ++++++++++------ src/Microsoft.Graph/Properties/AssemblyInfo.cs | 4 ++-- .../Microsoft.Graph.Core.Test.csproj | 3 +++ 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj b/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj index e208968d01f..57aa4322150 100644 --- a/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj +++ b/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj @@ -3,9 +3,9 @@ Microsoft Graph Core Client Library implements core functionality used by Microsoft Graph Client Libraries. © Microsoft Corporation. All rights reserved. Microsoft Graph Core Client Library - 1.13.0 - 1.13.0 - 1.13.0 + 1.14.0 + 1.14.0 + 1.14.0 Microsoft netstandard1.1;net45 false @@ -13,7 +13,7 @@ Microsoft.Graph.Core Microsoft Office365;Graph;GraphServiceClient;Outlook;OneDrive;AzureAD;GraphAPI;Productivity;SharePoint;Intune;SDK -January 2019 Release Summary (version 1.13.0) +February 2019 Release Summary (version 1.14.0-preview) - Authentication handler added. - Removed Newtonsoft.Json package reference upper bound limitation. @@ -38,7 +38,7 @@ January 2019 Release Summary (version 1.13.0) false 35MSSharedLib1024.snk true - 1.13.0 + 1.14.0-preview bin\Release\netstandard1.1\Microsoft.Graph.Core.xml diff --git a/src/Microsoft.Graph.Core/Properties/AssemblyInfo.cs b/src/Microsoft.Graph.Core/Properties/AssemblyInfo.cs index 8405ec6f90b..718d8cd3e52 100644 --- a/src/Microsoft.Graph.Core/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Graph.Core/Properties/AssemblyInfo.cs @@ -24,8 +24,8 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.13.0")] -[assembly: AssemblyFileVersion("1.13.0.0")] +[assembly: AssemblyVersion("1.14.0")] +[assembly: AssemblyFileVersion("1.14.0.0")] #if DEBUG [assembly: InternalsVisibleTo("Microsoft.Graph.Core.Test")] diff --git a/src/Microsoft.Graph/Microsoft.Graph.csproj b/src/Microsoft.Graph/Microsoft.Graph.csproj index ffe2a25b0f1..ec59e9e954b 100644 --- a/src/Microsoft.Graph/Microsoft.Graph.csproj +++ b/src/Microsoft.Graph/Microsoft.Graph.csproj @@ -3,9 +3,9 @@ Microsoft Graph Client Library allows you to call Office 365, Azure AD and other Microsoft services through a single unified developer experience. © Microsoft Corporation. All rights reserved. Microsoft Graph Client Library - 1.13.0 - 1.13.0 - 1.13.0 + 1.14.0 + 1.14.0 + 1.14.0 Microsoft netstandard1.1;net45 false @@ -13,19 +13,23 @@ Microsoft.Graph Microsoft Office365;Graph;GraphServiceClient;Outlook;OneDrive;AzureAD;GraphAPI;Productivity;SharePoint;Intune;SDK -January 2019 Release Summary (version 1.13.0) +February 2019 Release Summary (version 1.14.0-preview) New functionality - Added new Teams API functionality. - Added new Intune API functionality. +- Added new license API functionality. Updated functionality - Updated IntelliSense with new content. - Device is updated with the MemberOf relationship. - Group is updated with the isArchived property and Team relationship. -- User is updated with the JoinedTeams relationship. +- User is updated with the JoinedTeams relationship, EmployeeId, OtherMail. - Removed Newtonsoft.Json package reference upper bound limitation. +- Support for transitive members. +- Support for SharePoint root site access. +- Added CopyNotebook support. https://developer.microsoft.com/graph http://aka.ms/devservicesagreement @@ -45,7 +49,7 @@ Updated functionality false 35MSSharedLib1024.snk true - 1.13.0 + 1.14.0-preview bin\Release\Microsoft.Graph.xml diff --git a/src/Microsoft.Graph/Properties/AssemblyInfo.cs b/src/Microsoft.Graph/Properties/AssemblyInfo.cs index 01b2322cb9a..77d609cd9f8 100644 --- a/src/Microsoft.Graph/Properties/AssemblyInfo.cs +++ b/src/Microsoft.Graph/Properties/AssemblyInfo.cs @@ -24,8 +24,8 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.13.0")] -[assembly: AssemblyFileVersion("1.13.0.0")] +[assembly: AssemblyVersion("1.14.0")] +[assembly: AssemblyFileVersion("1.14.0.0")] #if DEBUG [assembly: InternalsVisibleTo("Microsoft.Graph.Test")] diff --git a/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj b/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj index 3acb619e6bf..eb7c7bb25ab 100644 --- a/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj +++ b/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj @@ -118,6 +118,9 @@ 1.4.0 + + 11.0.2 + From c1c7e6feb634eda56a27e7c3daa796e912bb853b Mon Sep 17 00:00:00 2001 From: Peter Wasonga Ombwa Date: Wed, 20 Feb 2019 11:16:51 -0800 Subject: [PATCH 2/5] Remove Newtonsoft reference form core.test --- .../Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj b/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj index eb7c7bb25ab..3acb619e6bf 100644 --- a/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj +++ b/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj @@ -118,9 +118,6 @@ 1.4.0 - - 11.0.2 - From ae9bb56d1749b84f52615d40c37db67a45a10451 Mon Sep 17 00:00:00 2001 From: Peter Wasonga Ombwa Date: Fri, 22 Feb 2019 11:43:11 -0800 Subject: [PATCH 3/5] Refactor HandlerOptions with defaults and exception handling --- .../Exceptions/ErrorConstants.cs | 3 +- .../Extensions/BaseRequestExtensions.cs | 8 +- .../AuthenticationHandler.cs | 0 .../Options}/AuthenticationHandlerOption.cs | 6 +- .../Options}/IAuthProviderOption.cs | 2 +- .../Options}/IMiddlewareOption.cs | 0 .../Options/RedirectHandlerOption.cs | 54 +++++++++++++ .../Middleware/Options/RetryHandlerOption.cs | 81 +++++++++++++++++++ .../RedirectHandler.cs | 7 +- .../{Handlers => Middleware}/RetryHandler.cs | 44 ++++++---- .../RedirectHandlerOption.cs | 24 ------ .../MiddlewareOptions/RetryHandlerOption.cs | 49 ----------- .../Extensions/BaseRequestExtensionsTests.cs | 8 +- .../Microsoft.Graph.Core.Test.csproj | 8 +- .../AuthenticationHandlerTests.cs | 0 .../Options/RedirectHandlerOptionTests.cs | 44 ++++++++++ .../Options/RetrytHandlerOptionTests.cs | 61 ++++++++++++++ .../{ => Middleware}/RedirectHandlerTests.cs | 12 +-- .../{ => Middleware}/RetryHandlerTests.cs | 13 ++- .../Extensions/BaseRequestExtensionsTests.cs | 8 +- .../AuthenticationHandlerTests.cs | 0 .../Options/RedirectHandlerOptionTests.cs | 49 +++++++++++ .../Options/RetrytHandlerOptionTests.cs | 81 +++++++++++++++++++ .../{ => Middleware}/RedirectHandlerTests.cs | 24 +++--- .../{ => Middleware}/RetryHandlerTests.cs | 10 +-- 25 files changed, 454 insertions(+), 142 deletions(-) rename src/Microsoft.Graph.Core/Requests/{Handlers => Middleware}/AuthenticationHandler.cs (100%) rename src/Microsoft.Graph.Core/Requests/{MiddlewareOptions => Middleware/Options}/AuthenticationHandlerOption.cs (79%) rename src/Microsoft.Graph.Core/Requests/{MiddlewareOptions => Middleware/Options}/IAuthProviderOption.cs (93%) rename src/Microsoft.Graph.Core/Requests/{MiddlewareOptions => Middleware/Options}/IMiddlewareOption.cs (100%) create mode 100644 src/Microsoft.Graph.Core/Requests/Middleware/Options/RedirectHandlerOption.cs create mode 100644 src/Microsoft.Graph.Core/Requests/Middleware/Options/RetryHandlerOption.cs rename src/Microsoft.Graph.Core/Requests/{Handlers => Middleware}/RedirectHandler.cs (96%) rename src/Microsoft.Graph.Core/Requests/{Handlers => Middleware}/RetryHandler.cs (78%) delete mode 100644 src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RedirectHandlerOption.cs delete mode 100644 src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RetryHandlerOption.cs rename tests/Microsoft.Graph.Core.Test/Requests/{ => Middleware}/AuthenticationHandlerTests.cs (100%) create mode 100644 tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs create mode 100644 tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs rename tests/Microsoft.Graph.Core.Test/Requests/{ => Middleware}/RedirectHandlerTests.cs (97%) rename tests/Microsoft.Graph.Core.Test/Requests/{ => Middleware}/RetryHandlerTests.cs (95%) rename tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/{ => Middleware}/AuthenticationHandlerTests.cs (100%) create mode 100644 tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs create mode 100644 tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs rename tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/{ => Middleware}/RedirectHandlerTests.cs (95%) rename tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/{ => Middleware}/RetryHandlerTests.cs (96%) diff --git a/src/Microsoft.Graph.Core/Exceptions/ErrorConstants.cs b/src/Microsoft.Graph.Core/Exceptions/ErrorConstants.cs index 4b36cd5349f..8688b2ac421 100644 --- a/src/Microsoft.Graph.Core/Exceptions/ErrorConstants.cs +++ b/src/Microsoft.Graph.Core/Exceptions/ErrorConstants.cs @@ -22,7 +22,7 @@ internal static class Codes internal static string TooManyRetries = "tooManyRetries"; - + internal static string MaximumValueExceeded = "MaximumValueExceeded"; } internal static class Messages @@ -53,6 +53,7 @@ internal static class Messages internal static string UnexpectedExceptionResponse = "Unexpected exception returned from the service."; + internal static string MaximumValueExceeded = "{0} exceeds the maximum value of {1}."; } } } diff --git a/src/Microsoft.Graph.Core/Extensions/BaseRequestExtensions.cs b/src/Microsoft.Graph.Core/Extensions/BaseRequestExtensions.cs index a11137c1e07..4f4ef42adb6 100644 --- a/src/Microsoft.Graph.Core/Extensions/BaseRequestExtensions.cs +++ b/src/Microsoft.Graph.Core/Extensions/BaseRequestExtensions.cs @@ -62,7 +62,7 @@ public static T WithPerRequestAuthProvider(this T baseRequest) where T : IBas } /// - /// Sets a ShouldRetry delegate to the default Retry Middleware Handler for this request. + /// Sets a ShouldRetry delegate to the default Retry Middleware Handler for this request. /// This only works with the default Retry Middleware Handler. /// If you use a custom Retry Middleware Handler, you have to handle it's retreival in your implementation. /// @@ -70,7 +70,7 @@ public static T WithPerRequestAuthProvider(this T baseRequest) where T : IBas /// The for the request. /// A for the request. /// - public static T WithShouldRetry(this T baseRequest, Func shouldRetry) where T : IBaseRequest + public static T WithShouldRetry(this T baseRequest, Func shouldRetry) where T : IBaseRequest { string retryOptionKey = typeof(RetryHandlerOption).ToString(); if (baseRequest.MiddlewareOptions.ContainsKey(retryOptionKey)) @@ -121,11 +121,11 @@ public static T WithMaxRedirects(this T baseRequest, int maxRedirects) where string redirectOptionKey = typeof(RedirectHandlerOption).ToString(); if (baseRequest.MiddlewareOptions.ContainsKey(redirectOptionKey)) { - (baseRequest.MiddlewareOptions[redirectOptionKey] as RedirectHandlerOption).MaxRedirects = maxRedirects; + (baseRequest.MiddlewareOptions[redirectOptionKey] as RedirectHandlerOption).MaxRedirect = maxRedirects; } else { - baseRequest.MiddlewareOptions.Add(redirectOptionKey, new RedirectHandlerOption { MaxRedirects = maxRedirects }); + baseRequest.MiddlewareOptions.Add(redirectOptionKey, new RedirectHandlerOption { MaxRedirect = maxRedirects }); } return baseRequest; } diff --git a/src/Microsoft.Graph.Core/Requests/Handlers/AuthenticationHandler.cs b/src/Microsoft.Graph.Core/Requests/Middleware/AuthenticationHandler.cs similarity index 100% rename from src/Microsoft.Graph.Core/Requests/Handlers/AuthenticationHandler.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/AuthenticationHandler.cs diff --git a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/AuthenticationHandlerOption.cs b/src/Microsoft.Graph.Core/Requests/Middleware/Options/AuthenticationHandlerOption.cs similarity index 79% rename from src/Microsoft.Graph.Core/Requests/MiddlewareOptions/AuthenticationHandlerOption.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/Options/AuthenticationHandlerOption.cs index 7208ade6428..a0c5b9edbc5 100644 --- a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/AuthenticationHandlerOption.cs +++ b/src/Microsoft.Graph.Core/Requests/Middleware/Options/AuthenticationHandlerOption.cs @@ -10,13 +10,13 @@ namespace Microsoft.Graph public class AuthenticationHandlerOption : IMiddlewareOption { /// - /// An Authentication Provider + /// An authentication provider /// internal IAuthenticationProvider AuthenticationProvider { get; set; } /// - /// An auth provider option property + /// An authentication provider option. /// - public IAuthProviderOption AuthProviderOption { get; set; } + public IAuthenticationProviderOption AuthenticationProviderOption { get; set; } } } diff --git a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/IAuthProviderOption.cs b/src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthProviderOption.cs similarity index 93% rename from src/Microsoft.Graph.Core/Requests/MiddlewareOptions/IAuthProviderOption.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthProviderOption.cs index 47b81929dda..ad9fee6546f 100644 --- a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/IAuthProviderOption.cs +++ b/src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthProviderOption.cs @@ -8,7 +8,7 @@ namespace Microsoft.Graph /// An interface used to pass auth provider options in a request. /// Auth providers will be incharge of implementing this interface and providing extensions to set it's values. /// - public interface IAuthProviderOption + public interface IAuthenticationProviderOption { /// /// Microsoft Graph scopes property. diff --git a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/IMiddlewareOption.cs b/src/Microsoft.Graph.Core/Requests/Middleware/Options/IMiddlewareOption.cs similarity index 100% rename from src/Microsoft.Graph.Core/Requests/MiddlewareOptions/IMiddlewareOption.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/Options/IMiddlewareOption.cs diff --git a/src/Microsoft.Graph.Core/Requests/Middleware/Options/RedirectHandlerOption.cs b/src/Microsoft.Graph.Core/Requests/Middleware/Options/RedirectHandlerOption.cs new file mode 100644 index 00000000000..1f538763bd4 --- /dev/null +++ b/src/Microsoft.Graph.Core/Requests/Middleware/Options/RedirectHandlerOption.cs @@ -0,0 +1,54 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +using System; +using System.Net.Http; + +namespace Microsoft.Graph +{ + /// + /// The redirect middleware option class + /// + public class RedirectHandlerOption : IMiddlewareOption + { + internal const int DEFAULT_MAX_REDIRECT = 5; + internal const int MAX_MAX_REDIRECT = 20; + /// + /// Constructs a new + /// + public RedirectHandlerOption() + { + + } + + + private int _maxRedirect = DEFAULT_MAX_REDIRECT; + + /// + /// The maximum number of redirects with a maximum value of 20. This defaults to 5 redirects. + /// + public int MaxRedirect + { + get { return _maxRedirect; } + set + { + if (value > MAX_MAX_REDIRECT) + { + throw new ServiceException( + new Error + { + Code = ErrorConstants.Codes.MaximumValueExceeded, + Message = string.Format(ErrorConstants.Messages.MaximumValueExceeded, "MaxRedirect", MAX_MAX_REDIRECT) + }); + } + _maxRedirect = value; + } + } + + /// + /// A delegate that's called to determine whether a response should be redirected or not. The delegate method should accept as it's parameter and return a . This defaults to true. + /// + public Func ShouldRedirect { get; set; } = (response) => true; + } +} diff --git a/src/Microsoft.Graph.Core/Requests/Middleware/Options/RetryHandlerOption.cs b/src/Microsoft.Graph.Core/Requests/Middleware/Options/RetryHandlerOption.cs new file mode 100644 index 00000000000..4ef9ad86ad8 --- /dev/null +++ b/src/Microsoft.Graph.Core/Requests/Middleware/Options/RetryHandlerOption.cs @@ -0,0 +1,81 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +namespace Microsoft.Graph +{ + using System; + using System.Net.Http; + + /// + /// The retry middleware option class + /// + public class RetryHandlerOption : IMiddlewareOption + { + internal const int DEFAULT_DELAY = 3; + internal const int DEFAULT_MAX_RETRY = 3; + internal const int MAX_MAX_RETRY = 10; + internal const int MAX_DELAY = 180; + + /// + /// Constructs a new + /// + public RetryHandlerOption() + { + } + + private int _delay = DEFAULT_DELAY; + /// + /// The waiting time in seconds before retrying a request with a maximum value of 180 seconds. This defaults to 3 seconds. + /// + public int Delay + { + get { return _delay; } + set + { + if (value > MAX_DELAY) + { + throw new ServiceException( + new Error + { + Code = ErrorConstants.Codes.MaximumValueExceeded, + Message = string.Format(ErrorConstants.Messages.MaximumValueExceeded, "Delay", MAX_DELAY) + }); + } + + _delay = value; + } + } + + private int _maxRetry = DEFAULT_MAX_RETRY; + /// + /// The maximum number of retries for a request with a maximum value of 10. This defaults to 3. + /// + public int MaxRetry + { + get + { + return _maxRetry; + } + set + { + if (value > MAX_MAX_RETRY) + { + throw new ServiceException( + new Error + { + Code = ErrorConstants.Codes.MaximumValueExceeded, + Message = string.Format(ErrorConstants.Messages.MaximumValueExceeded, "MaxRetry", MAX_MAX_RETRY) + }); + } + _maxRetry = value; + } + } + + /// + /// A delegate that's called to determine whether a request should be retried or not. + /// The delegate method should accept a delay time in seconds of, number of retry attempts and as it's parameters and return a . This defaults to true + /// + public Func ShouldRetry { get; set; } = (delay, attempt, response) => true; + } +} diff --git a/src/Microsoft.Graph.Core/Requests/Handlers/RedirectHandler.cs b/src/Microsoft.Graph.Core/Requests/Middleware/RedirectHandler.cs similarity index 96% rename from src/Microsoft.Graph.Core/Requests/Handlers/RedirectHandler.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/RedirectHandler.cs index 58d39d32bc3..e5ae9bbeb6b 100644 --- a/src/Microsoft.Graph.Core/Requests/Handlers/RedirectHandler.cs +++ b/src/Microsoft.Graph.Core/Requests/Middleware/RedirectHandler.cs @@ -53,8 +53,8 @@ protected override async Task SendAsync(HttpRequestMessage // send request first time to get response var response = await base.SendAsync(request, cancellationToken); - // check response status code - if (IsRedirect(response.StatusCode)) + // check response status code and redirect handler option + if (IsRedirect(response.StatusCode) && RedirectOption.ShouldRedirect(response) && RedirectOption.MaxRedirect > 0) { if (response.Headers.Location == null) { @@ -68,7 +68,7 @@ protected override async Task SendAsync(HttpRequestMessage var redirectCount = 0; - while (redirectCount < RedirectOption.MaxRedirects) + while (redirectCount < RedirectOption.MaxRedirect) { // general clone request with internal CloneAsync (see CloneAsync for details) extension method var newRequest = await response.RequestMessage.CloneAsync(); @@ -100,6 +100,7 @@ protected override async Task SendAsync(HttpRequestMessage } redirectCount++; } + throw new ServiceException( new Error { diff --git a/src/Microsoft.Graph.Core/Requests/Handlers/RetryHandler.cs b/src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs similarity index 78% rename from src/Microsoft.Graph.Core/Requests/Handlers/RetryHandler.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs index 002ee86c518..aedd03501b9 100644 --- a/src/Microsoft.Graph.Core/Requests/Handlers/RetryHandler.cs +++ b/src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs @@ -60,7 +60,7 @@ protected async override Task SendAsync(HttpRequestMessage var response = await base.SendAsync(httpRequest, cancellationToken); - if (RetryOption.ShouldRetry(response) && httpRequest.IsBuffered()) + if(IsRetry(response) && httpRequest.IsBuffered() && RetryOption.MaxRetry > 0 && RetryOption.ShouldRetry(RetryOption.Delay, 0, response)) { response = await SendRetryAsync(response, cancellationToken); } @@ -74,13 +74,13 @@ protected async override Task SendAsync(HttpRequestMessage /// The which is returned and includes the HTTP request needs to be retried. /// The for the retry. /// - public async Task SendRetryAsync(HttpResponseMessage response, CancellationToken cancellationToken) + private async Task SendRetryAsync(HttpResponseMessage response, CancellationToken cancellationToken) { int retryCount = 0; while (retryCount < RetryOption.MaxRetry) { // Call Delay method to get delay time from response's Retry-After header or by exponential backoff - Task delay = Delay(response, retryCount, cancellationToken); + Task delay = Delay(response, retryCount, RetryOption.Delay, cancellationToken); // general clone request with internal CloneAsync (see CloneAsync for details) extension method var request = await response.RequestMessage.CloneAsync(); @@ -95,11 +95,10 @@ public async Task SendRetryAsync(HttpResponseMessage respon // Call base.SendAsync to send the request response = await base.SendAsync(request, cancellationToken); - if (!RetryOption.ShouldRetry(response) || !request.IsBuffered()) + if (!IsRetry(response) || !request.IsBuffered() || !RetryOption.ShouldRetry(RetryOption.Delay, retryCount, response)) { return response; } - } throw new ServiceException( new Error @@ -129,34 +128,47 @@ private void AddOrUpdateRetryAttempt(HttpRequestMessage request, int retry_count /// /// The returned. /// The retry counts + /// Delay value in seconds. /// The cancellationToken for the Http request /// The for delay operation. - public Task Delay(HttpResponseMessage response, int retry_count, CancellationToken cancellationToken) + public Task Delay(HttpResponseMessage response, int retry_count, int delay, CancellationToken cancellationToken) { - - TimeSpan delay = TimeSpan.FromMilliseconds(0); + //TimeSpan delayTimeSpan = TimeSpan.FromMilliseconds(0); HttpHeaders headers = response.Headers; + double delayInSeconds = RetryOption.Delay; if (headers.TryGetValues(RETRY_AFTER, out IEnumerable values)) { string retry_after = values.First(); if (Int32.TryParse(retry_after, out int delay_seconds)) { - delay = TimeSpan.FromSeconds(delay_seconds); + delayInSeconds = delay_seconds; } } else { + m_pow = Math.Pow(2, retry_count); + delayInSeconds = m_pow * RetryOption.Delay; + } - m_pow = Math.Pow(2, retry_count); // m_pow = Pow(2, retry_count) + TimeSpan delayTimeSpan = TimeSpan.FromSeconds(Math.Min(delayInSeconds, RetryHandlerOption.MAX_DELAY)); - double delay_time = m_pow * DELAY_MILLISECONDS; - - delay = TimeSpan.FromMilliseconds(delay_time); - } - return Task.Delay(delay, cancellationToken); + return Task.Delay(delayTimeSpan, cancellationToken); } - + /// + /// Check the HTTP response's status to determine whether it should be retried or not. + /// + /// The returned. + /// + private bool IsRetry(HttpResponseMessage response) + { + if ((response.StatusCode == HttpStatusCode.ServiceUnavailable || + response.StatusCode == (HttpStatusCode)429)) + { + return true; + } + return false; + } } } diff --git a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RedirectHandlerOption.cs b/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RedirectHandlerOption.cs deleted file mode 100644 index 9dce97945c5..00000000000 --- a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RedirectHandlerOption.cs +++ /dev/null @@ -1,24 +0,0 @@ -// ------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. -// ------------------------------------------------------------------------------ - -namespace Microsoft.Graph -{ - /// - /// The redirect middleware option class - /// - public class RedirectHandlerOption : IMiddlewareOption - { - /// - /// Constructs a new - /// - public RedirectHandlerOption() - { - - } - /// - /// A MaxRedirects property - /// - public int MaxRedirects { get; set; } = 5; - } -} diff --git a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RetryHandlerOption.cs b/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RetryHandlerOption.cs deleted file mode 100644 index 05c8e3bd189..00000000000 --- a/src/Microsoft.Graph.Core/Requests/MiddlewareOptions/RetryHandlerOption.cs +++ /dev/null @@ -1,49 +0,0 @@ -// ------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. -// ------------------------------------------------------------------------------ - -namespace Microsoft.Graph -{ - using System; - using System.Net; - using System.Net.Http; - - /// - /// The retry middleware option class - /// - public class RetryHandlerOption : IMiddlewareOption - { - /// - /// Constructs a new - /// - public RetryHandlerOption() - { - ShouldRetry = (response) => IsRetry(response); - } - - /// - /// MaxRetry property - /// - public int MaxRetry { set; get; } = 10; - - /// - /// A ShouldRetry delegate - /// - public Func ShouldRetry { get; set; } - - /// - /// Check the HTTP response's status to determine whether it should be retried or not. - /// - /// The returned. - /// - private bool IsRetry(HttpResponseMessage response) - { - if ((response.StatusCode == HttpStatusCode.ServiceUnavailable || - response.StatusCode == (HttpStatusCode)429)) - { - return true; - } - return false; - } - } -} diff --git a/tests/Microsoft.Graph.Core.Test/Extensions/BaseRequestExtensionsTests.cs b/tests/Microsoft.Graph.Core.Test/Extensions/BaseRequestExtensionsTests.cs index 7f136f51a9f..b33ab9d832a 100644 --- a/tests/Microsoft.Graph.Core.Test/Extensions/BaseRequestExtensionsTests.cs +++ b/tests/Microsoft.Graph.Core.Test/Extensions/BaseRequestExtensionsTests.cs @@ -38,11 +38,13 @@ public void WithShouldRetry_ShouldDelegateToRetryOption() { using (HttpResponseMessage httpResponseMessage = new HttpResponseMessage()) { + int delay = 1; + int attempt = 1; var baseRequest = new BaseRequest(requestUrl, baseClient); - baseRequest.WithShouldRetry((response) => true); + baseRequest.WithShouldRetry((d, a, r) => false); Assert.IsInstanceOfType(baseRequest.GetHttpRequestMessage().Properties[typeof(GraphRequestContext).ToString()], typeof(GraphRequestContext), "Unexpected request context."); - Assert.IsTrue(baseRequest.GetHttpRequestMessage().GetMiddlewareOption().ShouldRetry(httpResponseMessage), "Unexpected middleware option."); + Assert.IsFalse(baseRequest.GetHttpRequestMessage().GetMiddlewareOption().ShouldRetry(delay, attempt, httpResponseMessage), "Unexpected middleware option."); } } @@ -63,7 +65,7 @@ public void WithMaxRedirects_ShouldAddMaxRedirectsToRedirectOption() baseRequest.WithMaxRedirects(4); Assert.IsInstanceOfType(baseRequest.GetHttpRequestMessage().Properties[typeof(GraphRequestContext).ToString()], typeof(GraphRequestContext), "Unexpected request context"); - Assert.AreEqual(4, baseRequest.GetHttpRequestMessage().GetMiddlewareOption().MaxRedirects, "Unexpected max redirects value."); + Assert.AreEqual(4, baseRequest.GetHttpRequestMessage().GetMiddlewareOption().MaxRedirect, "Unexpected max redirects value."); } [TestMethod] diff --git a/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj b/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj index 3acb619e6bf..3ffdd35659d 100644 --- a/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj +++ b/tests/Microsoft.Graph.Core.Test/Microsoft.Graph.Core.Test.csproj @@ -62,11 +62,13 @@ - + - - + + + + diff --git a/tests/Microsoft.Graph.Core.Test/Requests/AuthenticationHandlerTests.cs b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/AuthenticationHandlerTests.cs similarity index 100% rename from tests/Microsoft.Graph.Core.Test/Requests/AuthenticationHandlerTests.cs rename to tests/Microsoft.Graph.Core.Test/Requests/Middleware/AuthenticationHandlerTests.cs diff --git a/tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs new file mode 100644 index 00000000000..1ee3058f17c --- /dev/null +++ b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs @@ -0,0 +1,44 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +namespace Microsoft.Graph.Core.Test.Requests.Middleware.Options +{ + using System; + using System.Net.Http; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class RedirectHandlerOptionTests + { + [TestMethod] + public void RedirectHandlerOption_ShouldUseDefaultValuesIfNotSpecified() + { + var retryOptions = new RedirectHandlerOption(); + Assert.AreEqual(RedirectHandlerOption.DEFAULT_MAX_REDIRECT, retryOptions.MaxRedirect, "Invalid default MaxRedirectt set."); + Assert.IsTrue(retryOptions.ShouldRedirect(null), "Invalid default ShouldRedirect output."); + } + + [TestMethod] + public void RedirectHandlerOption_ShouldThrowMaximumValueExceededExceptionForMaxRedirect() + { + ServiceException ex = Assert.ThrowsException(() => new RedirectHandlerOption() { MaxRedirect = 21 }); + Assert.AreEqual(ex.Error.Code, ErrorConstants.Codes.MaximumValueExceeded, "Invalid exception code."); + Assert.AreEqual(ex.Error.Message, string.Format(ErrorConstants.Messages.MaximumValueExceeded, "MaxRedirect", RedirectHandlerOption.MAX_MAX_REDIRECT), "Invalid exception message."); + } + + [TestMethod] + public void RedirectHandlerOption_ShouldAcceptCorrectValue() + { + int maxRedirect = 15; + var retryOptions = new RedirectHandlerOption() { MaxRedirect = maxRedirect, ShouldRedirect = ShouldRedirect }; + Assert.AreEqual(maxRedirect, retryOptions.MaxRedirect, "Invalid MaxRedirect time set."); + Assert.AreEqual(ShouldRedirect, retryOptions.ShouldRedirect, "Invalid ShouldRedirect delegate set."); + } + + private bool ShouldRedirect(HttpResponseMessage rwsponse) + { + return false; + } + } +} diff --git a/tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs new file mode 100644 index 00000000000..927f963bf1d --- /dev/null +++ b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs @@ -0,0 +1,61 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +namespace Microsoft.Graph.Core.Test.Requests.Middleware.Options +{ + using Microsoft.VisualStudio.TestTools.UnitTesting; + using System.Net.Http; + + [TestClass] + public class RetrytHandlerOptionTests + { + [TestMethod] + public void RetrytHandlerOption_ShouldUseDefaultValuesIfNotSpecified() + { + var retryOptions = new RetryHandlerOption(); + Assert.AreEqual(RetryHandlerOption.DEFAULT_DELAY, retryOptions.Delay, "Invalid default delay time set."); + Assert.AreEqual(RetryHandlerOption.DEFAULT_MAX_RETRY, retryOptions.MaxRetry, "Invalid default maximum retry count set."); + Assert.IsTrue(retryOptions.ShouldRetry(0, 0, null), "Invalid default ShouldRetry output."); + } + + [TestMethod] + public void RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForDelayAndMaxRetry() + { + ServiceException ex = Assert.ThrowsException(() => new RetryHandlerOption() { Delay = 181, MaxRetry = 11 }); + Assert.AreEqual(ex.Error.Code, ErrorConstants.Codes.MaximumValueExceeded, "Invalid exception."); + } + + [TestMethod] + public void RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForDelay() + { + ServiceException ex = Assert.ThrowsException(() => new RetryHandlerOption() { Delay = 200 }); + Assert.AreEqual(ex.Error.Code, ErrorConstants.Codes.MaximumValueExceeded, "Invalid exception code."); + Assert.AreEqual(ex.Error.Message, string.Format(ErrorConstants.Messages.MaximumValueExceeded, "Delay", RetryHandlerOption.MAX_DELAY), "Invalid exception message."); + } + + [TestMethod] + public void RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForMaxRetry() + { + ServiceException ex = Assert.ThrowsException(() => new RetryHandlerOption() { Delay = 180, MaxRetry = 15 }); + Assert.AreEqual(ex.Error.Code, ErrorConstants.Codes.MaximumValueExceeded, "Invalid exception code."); + Assert.AreEqual(ex.Error.Message, string.Format(ErrorConstants.Messages.MaximumValueExceeded, "MaxRetry", RetryHandlerOption.MAX_MAX_RETRY), "Invalid exception message."); + } + + [TestMethod] + public void RetrytHandlerOption_ShouldAcceptCorrectValue() + { + int delay = 20; + int maxRetry = 5; + var retryOptions = new RetryHandlerOption() { Delay = delay, MaxRetry = maxRetry, ShouldRetry = ShouldRetry }; + Assert.AreEqual(delay, retryOptions.Delay, "Invalid delay time set."); + Assert.AreEqual(maxRetry, retryOptions.MaxRetry, "Invalid MaxRetry set."); + Assert.AreEqual(ShouldRetry, retryOptions.ShouldRetry, "Invalid ShouldRetry delegate set."); + } + + private bool ShouldRetry(int delay, int attempts, HttpResponseMessage rwsponse) + { + return false; + } + } +} diff --git a/tests/Microsoft.Graph.Core.Test/Requests/RedirectHandlerTests.cs b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/RedirectHandlerTests.cs similarity index 97% rename from tests/Microsoft.Graph.Core.Test/Requests/RedirectHandlerTests.cs rename to tests/Microsoft.Graph.Core.Test/Requests/Middleware/RedirectHandlerTests.cs index b217ca63139..8870b9585a1 100644 --- a/tests/Microsoft.Graph.Core.Test/Requests/RedirectHandlerTests.cs +++ b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/RedirectHandlerTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.Graph.Core.Test.Requests [TestClass] - public class RedirectHandlerTests + public class RedirectHandlerTests { private MockRedirectHandler testHttpMessageHandler; private RedirectHandler redirectHandler; @@ -42,7 +42,7 @@ public void RedirectHandler_Constructor() { Assert.IsNull(redirect.InnerHandler, "HttpMessageHandler initialized."); Assert.IsNotNull(redirect.RedirectOption, "redirect option not initialized"); - Assert.AreEqual(5, redirect.RedirectOption.MaxRedirects, "Unexpected max redirect set"); // default MaxRedirects is 5 + Assert.AreEqual(5, redirect.RedirectOption.MaxRedirect, "Unexpected max redirect set"); // default MaxRedirects is 5 Assert.IsInstanceOfType(redirect, typeof(RedirectHandler), "Unexpected redirect handler set."); } } @@ -53,18 +53,18 @@ public void RedirectHandler_HttpMessageHandlerConstructor() Assert.IsNotNull(redirectHandler.InnerHandler, "HttpMessageHandler not initialized."); Assert.AreEqual(redirectHandler.InnerHandler, testHttpMessageHandler, "Unexpected message handler set."); Assert.IsNotNull(redirectHandler.RedirectOption, "Redirect option not initialized"); - Assert.AreEqual(5, redirectHandler.RedirectOption.MaxRedirects, "Unexpected max redirect set"); // default MaxRedirects is 5 + Assert.AreEqual(5, redirectHandler.RedirectOption.MaxRedirect, "Unexpected max redirect set"); // default MaxRedirects is 5 Assert.IsInstanceOfType(redirectHandler, typeof(RedirectHandler), "Unexpected redirect handler set."); } [TestMethod] public void RedirectHandler_RedirectOptionConstructor() { - using (RedirectHandler redirect = new RedirectHandler(new RedirectHandlerOption { MaxRedirects = 2 })) + using (RedirectHandler redirect = new RedirectHandler(new RedirectHandlerOption { MaxRedirect = 2 })) { Assert.IsNull(redirect.InnerHandler, "HttpMessageHandler initialized"); Assert.IsNotNull(redirect.RedirectOption, "Redirect option not initialized"); - Assert.AreEqual(2, redirect.RedirectOption.MaxRedirects, "Unexpected max redirects set"); + Assert.AreEqual(2, redirect.RedirectOption.MaxRedirect, "Unexpected max redirects set"); Assert.IsInstanceOfType(redirect, typeof(RedirectHandler), "Unexpected redirect handler set"); } } @@ -200,7 +200,7 @@ public async Task ExceedMaxRedirectsShouldReturn() _response2.Headers.Location = new Uri("http://example.org/foo"); this.testHttpMessageHandler.SetHttpResponse(_response1, _response2); - + try { await this.invoker.SendAsync(httpRequestMessage, new CancellationToken()); diff --git a/tests/Microsoft.Graph.Core.Test/Requests/RetryHandlerTests.cs b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/RetryHandlerTests.cs similarity index 95% rename from tests/Microsoft.Graph.Core.Test/Requests/RetryHandlerTests.cs rename to tests/Microsoft.Graph.Core.Test/Requests/Middleware/RetryHandlerTests.cs index d53f1aa1e16..25a548dfc3a 100644 --- a/tests/Microsoft.Graph.Core.Test/Requests/RetryHandlerTests.cs +++ b/tests/Microsoft.Graph.Core.Test/Requests/Middleware/RetryHandlerTests.cs @@ -46,7 +46,7 @@ public void RedtryHandler_Constructor() { Assert.IsNull(retry.InnerHandler, "HttpMessageHandler initialized."); Assert.IsNotNull(retry.RetryOption, "Retry option not initialized"); - Assert.AreEqual(10, retry.RetryOption.MaxRetry, "Unexpected max retry set"); // default MaxRetry is 10 + Assert.AreEqual(RetryHandlerOption.DEFAULT_MAX_RETRY, retry.RetryOption.MaxRetry, "Unexpected max retry set"); Assert.IsInstanceOfType(retry, typeof(RetryHandler), "Unexpected redtry handler set."); } } @@ -57,7 +57,7 @@ public void retryHandler_HttpMessageHandlerConstructor() { Assert.IsNotNull(retryHandler.InnerHandler, "HttpMessageHandler not initialized."); Assert.IsNotNull(retryHandler.RetryOption, "Retry option not initialized"); - Assert.AreEqual(10, retryHandler.RetryOption.MaxRetry, "Unexpected max retry set"); // default MaxRetry is 10 + Assert.AreEqual(RetryHandlerOption.DEFAULT_MAX_RETRY, retryHandler.RetryOption.MaxRetry, "Unexpected max retry set"); // default MaxRetry is 10 Assert.AreEqual(retryHandler.InnerHandler, testHttpMessageHandler, "Unexpected message handler set."); Assert.IsInstanceOfType(retryHandler, typeof(RetryHandler), "Unexpected redirect handler set."); } @@ -65,7 +65,7 @@ public void retryHandler_HttpMessageHandlerConstructor() [TestMethod] public void retryHandler_RetryOptionConstructor() { - using (RetryHandler retry = new RetryHandler(new RetryHandlerOption { MaxRetry = 5, ShouldRetry = (response) => true })) + using (RetryHandler retry = new RetryHandler(new RetryHandlerOption { MaxRetry = 5, ShouldRetry = (retryInSeconds, attemptCount, response) => true })) { Assert.IsNull(retry.InnerHandler, "HttpMessageHandler initialized"); Assert.IsNotNull(retry.RetryOption, "Retry option not initialized"); @@ -219,9 +219,6 @@ public async Task ExceedMaxRetryShouldReturn(HttpStatusCode statusCode) Assert.AreEqual(values.Count(), 1, "There are multiple values for Retry-Attemp header."); Assert.AreEqual(values.First(), 10.ToString(), "The value of Retry-Attemp header is wrong."); } - - - } [DataTestMethod] @@ -278,12 +275,12 @@ public async Task ShouldDelayBasedOnExponentialBackOff(HttpStatusCode statusCode } - private async Task DelayTestWithMessage(HttpResponseMessage response, int count, string message) + private async Task DelayTestWithMessage(HttpResponseMessage response, int count, string message, int delay = RetryHandlerOption.MAX_DELAY) { Message = message; await Task.Run(async () => { - await this.retryHandler.Delay(response, count, new CancellationToken()); + await this.retryHandler.Delay(response, count, delay, new CancellationToken()); Message += " Work " + count.ToString(); }); diff --git a/tests/Microsoft.Graph.DotnetCore.Core.Test/Extensions/BaseRequestExtensionsTests.cs b/tests/Microsoft.Graph.DotnetCore.Core.Test/Extensions/BaseRequestExtensionsTests.cs index c0dfc0c1f9b..cadb2c09ce9 100644 --- a/tests/Microsoft.Graph.DotnetCore.Core.Test/Extensions/BaseRequestExtensionsTests.cs +++ b/tests/Microsoft.Graph.DotnetCore.Core.Test/Extensions/BaseRequestExtensionsTests.cs @@ -37,11 +37,13 @@ public void WithShouldRetry_ShouldDelegateToRetryOption() { using (HttpResponseMessage httpResponseMessage = new HttpResponseMessage()) { + int delay = 1; + int attempt = 1; var baseRequest = new BaseRequest(requestUrl, baseClient); - baseRequest.WithShouldRetry((response) => true); + baseRequest.WithShouldRetry((d, a, r) => false); Assert.IsType(baseRequest.GetHttpRequestMessage().Properties[typeof(GraphRequestContext).ToString()]); - Assert.True(baseRequest.GetHttpRequestMessage().GetMiddlewareOption().ShouldRetry(httpResponseMessage)); + Assert.False(baseRequest.GetHttpRequestMessage().GetMiddlewareOption().ShouldRetry(delay, attempt, httpResponseMessage)); } } @@ -62,7 +64,7 @@ public void WithMaxRedirects_ShouldAddMaxRedirectsToRedirectOption() baseRequest.WithMaxRedirects(4); Assert.IsType(baseRequest.GetHttpRequestMessage().Properties[typeof(GraphRequestContext).ToString()]); - Assert.Equal(4, baseRequest.GetHttpRequestMessage().GetMiddlewareOption().MaxRedirects); + Assert.Equal(4, baseRequest.GetHttpRequestMessage().GetMiddlewareOption().MaxRedirect); } [Fact] diff --git a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/AuthenticationHandlerTests.cs b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/AuthenticationHandlerTests.cs similarity index 100% rename from tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/AuthenticationHandlerTests.cs rename to tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/AuthenticationHandlerTests.cs diff --git a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs new file mode 100644 index 00000000000..500ff75cdc0 --- /dev/null +++ b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RedirectHandlerOptionTests.cs @@ -0,0 +1,49 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +namespace Microsoft.Graph.DotnetCore.Core.Test.Requests.Middleware.Options +{ + using System.Net.Http; + using Xunit; + + public class RedirectHandlerOptionTests + { + [Fact] + public void RedirectHandlerOption_ShouldUseDefaultValuesIfNotSpecified() + { + var retryOptions = new RedirectHandlerOption(); + Assert.Equal(RedirectHandlerOption.DEFAULT_MAX_REDIRECT, retryOptions.MaxRedirect); + Assert.True(retryOptions.ShouldRedirect(null)); + } + + [Fact] + public void RedirectHandlerOption_RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForMaxRedirect() + { + try + { + Assert.Throws(() => new RedirectHandlerOption() { MaxRedirect = 21 }); + } + catch (ServiceException exception) + { + Assert.Equal(exception.Error.Code, ErrorConstants.Codes.MaximumValueExceeded); + Assert.Equal(exception.Error.Message, string.Format(ErrorConstants.Messages.MaximumValueExceeded, "MaxRedirect", RedirectHandlerOption.MAX_MAX_REDIRECT)); + throw; + } + } + + [Fact] + public void RedirectHandlerOption_RetrytHandlerOption_ShouldAcceptCorrectValue() + { + int maxRedirect = 15; + var retryOptions = new RedirectHandlerOption() { MaxRedirect = maxRedirect, ShouldRedirect = ShouldRedirect }; + Assert.Equal(maxRedirect, retryOptions.MaxRedirect); + Assert.Equal(ShouldRedirect, retryOptions.ShouldRedirect); + } + + private bool ShouldRedirect(HttpResponseMessage rwsponse) + { + return false; + } + } +} diff --git a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs new file mode 100644 index 00000000000..93e2794872b --- /dev/null +++ b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/Options/RetrytHandlerOptionTests.cs @@ -0,0 +1,81 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +namespace Microsoft.Graph.DotnetCore.Core.Test.Requests.Middleware.Options +{ + using System.Net.Http; + using Xunit; + + public class RetrytHandlerOptionTests + { + [Fact] + public void RetrytHandlerOption_ShouldUseDefaultValuesIfNotSpecified() + { + var retryOptions = new RetryHandlerOption(); + Assert.Equal(RetryHandlerOption.DEFAULT_DELAY, retryOptions.Delay); + Assert.Equal(RetryHandlerOption.DEFAULT_MAX_RETRY, retryOptions.MaxRetry); + Assert.True(retryOptions.ShouldRetry(0, 0, null)); + } + + [Fact] + public void RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForDelayAndMaxRetry() + { + try + { + Assert.Throws(() => new RetryHandlerOption() { Delay = 181, MaxRetry = 11 }); + } + catch (ServiceException exception) + { + Assert.Equal(exception.Error.Code, ErrorConstants.Codes.MaximumValueExceeded); + throw; + } + } + + [Fact] + public void RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForDelay() + { + try + { + Assert.Throws(() => new RetryHandlerOption() { Delay = 200 }); + } + catch (ServiceException exception) + { + Assert.Equal(exception.Error.Code, ErrorConstants.Codes.MaximumValueExceeded); + Assert.Equal(exception.Error.Message, string.Format(ErrorConstants.Messages.MaximumValueExceeded, "Delay", RetryHandlerOption.MAX_DELAY)); + throw; + } + } + + [Fact] + public void RetrytHandlerOption_ShouldThrowMaximumValueExceededExceptionForMaxRetry() + { + try + { + Assert.Throws(() => new RetryHandlerOption() { Delay = 180, MaxRetry = 15 }); + } + catch (ServiceException exception) + { + Assert.Equal(exception.Error.Code, ErrorConstants.Codes.MaximumValueExceeded); + Assert.Equal(exception.Error.Message, string.Format(ErrorConstants.Messages.MaximumValueExceeded, "MaxRetry", RetryHandlerOption.MAX_MAX_RETRY)); + throw; + } + } + + [Fact] + public void RetrytHandlerOption_ShouldAcceptCorrectValue() + { + int delay = 20; + int maxRetry = 5; + var retryOptions = new RetryHandlerOption() { Delay = delay, MaxRetry = maxRetry, ShouldRetry = ShouldRetry }; + Assert.Equal(delay, retryOptions.Delay); + Assert.Equal(maxRetry, retryOptions.MaxRetry); + Assert.Equal(ShouldRetry, retryOptions.ShouldRetry); + } + + private bool ShouldRetry(int delay, int attempts, HttpResponseMessage rwsponse) + { + return false; + } + } +} diff --git a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/RedirectHandlerTests.cs b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/RedirectHandlerTests.cs similarity index 95% rename from tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/RedirectHandlerTests.cs rename to tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/RedirectHandlerTests.cs index 608580c07c0..b87e588646e 100644 --- a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/RedirectHandlerTests.cs +++ b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/RedirectHandlerTests.cs @@ -18,7 +18,7 @@ public class RedirectHandlerTests : IDisposable private MockRedirectHandler testHttpMessageHandler; private RedirectHandler redirectHandler; private HttpMessageInvoker invoker; - + public RedirectHandlerTests() { @@ -39,7 +39,7 @@ public void RedirectHandler_Constructor() { Assert.Null(redirect.InnerHandler); Assert.NotNull(redirect.RedirectOption); - Assert.Equal(5, redirect.RedirectOption.MaxRedirects); // default MaxRedirects is 5 + Assert.Equal(5, redirect.RedirectOption.MaxRedirect); // default MaxRedirects is 5 Assert.IsType(typeof(RedirectHandler), redirect); } } @@ -49,7 +49,7 @@ public void RedirectHandler_HttpMessageHandlerConstructor() { Assert.NotNull(this.redirectHandler.InnerHandler); Assert.NotNull(redirectHandler.RedirectOption); - Assert.Equal(5, redirectHandler.RedirectOption.MaxRedirects); // default MaxRedirects is 5 + Assert.Equal(5, redirectHandler.RedirectOption.MaxRedirect); // default MaxRedirects is 5 Assert.Equal(this.redirectHandler.InnerHandler, this.testHttpMessageHandler); Assert.IsType(typeof(RedirectHandler), this.redirectHandler); } @@ -57,11 +57,11 @@ public void RedirectHandler_HttpMessageHandlerConstructor() [Fact] public void RedirectHandler_RedirectOptionConstructor() { - using (RedirectHandler redirect = new RedirectHandler(new RedirectHandlerOption { MaxRedirects = 2 })) + using (RedirectHandler redirect = new RedirectHandler(new RedirectHandlerOption { MaxRedirect = 2 })) { Assert.Null(redirect.InnerHandler); Assert.NotNull(redirect.RedirectOption); - Assert.Equal(2, redirect.RedirectOption.MaxRedirects); + Assert.Equal(2, redirect.RedirectOption.MaxRedirect); Assert.IsType(typeof(RedirectHandler), redirect); } } @@ -74,7 +74,7 @@ public async Task OkStatusShouldPassThrough() var redirectResponse = new HttpResponseMessage(HttpStatusCode.OK); this.testHttpMessageHandler.SetHttpResponse(redirectResponse); - var response =await this.invoker.SendAsync(httpRequestMessage, new CancellationToken()); + var response = await this.invoker.SendAsync(httpRequestMessage, new CancellationToken()); Assert.Equal(response.StatusCode, HttpStatusCode.OK); Assert.Same(response.RequestMessage, httpRequestMessage); @@ -179,7 +179,7 @@ public async Task RedirectWithSameHostShouldKeepAuthHeader() this.testHttpMessageHandler.SetHttpResponse(redirectResponse, new HttpResponseMessage(HttpStatusCode.OK)); var response = await invoker.SendAsync(httpRequestMessage, new CancellationToken()); - + Assert.NotSame(response.RequestMessage, httpRequestMessage); Assert.Equal(response.RequestMessage.RequestUri.Host, httpRequestMessage.RequestUri.Host); Assert.NotNull(response.RequestMessage.Headers.Authorization); @@ -197,15 +197,13 @@ public async Task ExceedMaxRedirectsShouldThrowsException() _response2.Headers.Location = new Uri("http://example.org/foo"); this.testHttpMessageHandler.SetHttpResponse(_response1, _response2); - - ServiceException exception = await Assert.ThrowsAsync (async () => await this.invoker.SendAsync( - httpRequestMessage, CancellationToken.None)); - + + ServiceException exception = await Assert.ThrowsAsync(async () => await this.invoker.SendAsync( + httpRequestMessage, CancellationToken.None)); + Assert.True(exception.IsMatch(ErrorConstants.Codes.TooManyRedirects)); Assert.Equal(String.Format(ErrorConstants.Messages.TooManyRedirectsFormatString, 5), exception.Error.Message); Assert.IsType(typeof(ServiceException), exception); } - - } } diff --git a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/RetryHandlerTests.cs b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/RetryHandlerTests.cs similarity index 96% rename from tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/RetryHandlerTests.cs rename to tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/RetryHandlerTests.cs index b7188885b4a..b89e1c05f20 100644 --- a/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/RetryHandlerTests.cs +++ b/tests/Microsoft.Graph.DotnetCore.Core.Test/Requests/Middleware/RetryHandlerTests.cs @@ -43,7 +43,7 @@ public void retryHandler_Constructor() { Assert.Null(retry.InnerHandler); Assert.NotNull(retry.RetryOption); - Assert.Equal(10, retry.RetryOption.MaxRetry); // default MaxRetry is 10 + Assert.Equal(RetryHandlerOption.DEFAULT_MAX_RETRY, retry.RetryOption.MaxRetry); Assert.IsType(typeof(RetryHandler), retry); } } @@ -54,7 +54,7 @@ public void retryHandler_HttpMessageHandlerConstructor() { Assert.NotNull(retryHandler.InnerHandler); Assert.NotNull(retryHandler.RetryOption); - Assert.Equal(10, retryHandler.RetryOption.MaxRetry); // default MaxRetry is 10 + Assert.Equal(RetryHandlerOption.DEFAULT_MAX_RETRY, retryHandler.RetryOption.MaxRetry); Assert.Equal(retryHandler.InnerHandler, testHttpMessageHandler); Assert.IsType(typeof(RetryHandler), retryHandler); } @@ -62,7 +62,7 @@ public void retryHandler_HttpMessageHandlerConstructor() [Fact] public void retryHandler_RetryOptionConstructor() { - using (RetryHandler retry = new RetryHandler(new RetryHandlerOption { MaxRetry = 5, ShouldRetry = (response) => true })) + using (RetryHandler retry = new RetryHandler(new RetryHandlerOption { MaxRetry = 5, ShouldRetry = (d, a, r) => true })) { Assert.Null(retry.InnerHandler); Assert.NotNull(retry.RetryOption); @@ -275,12 +275,12 @@ public async Task ShouldRetrytBasedOnRetryAfter(HttpStatusCode statusCode) Assert.NotSame(response.RequestMessage, httpRequestMessage); } - private async Task DelayTestWithMessage(HttpResponseMessage response, int count, string message) + private async Task DelayTestWithMessage(HttpResponseMessage response, int count, string message, int delay = RetryHandlerOption.MAX_DELAY) { Message = message; await Task.Run(async () => { - await this.retryHandler.Delay(response, count, new CancellationToken()); + await this.retryHandler.Delay(response, count, delay, new CancellationToken()); Message += " Work " + count.ToString(); }); From b6fbd7a3759704448a5e14692f14fb852501249a Mon Sep 17 00:00:00 2001 From: Peter Wasonga Ombwa Date: Fri, 22 Feb 2019 14:10:38 -0800 Subject: [PATCH 4/5] Add GraphUserAccount to request context --- .../Requests/GraphRequestContext.cs | 5 +++ .../Requests/Middleware/GraphUserAccount.cs | 32 +++++++++++++++++++ ...on.cs => IAuthenticationProviderOption.cs} | 0 3 files changed, 37 insertions(+) create mode 100644 src/Microsoft.Graph.Core/Requests/Middleware/GraphUserAccount.cs rename src/Microsoft.Graph.Core/Requests/Middleware/Options/{IAuthProviderOption.cs => IAuthenticationProviderOption.cs} (100%) diff --git a/src/Microsoft.Graph.Core/Requests/GraphRequestContext.cs b/src/Microsoft.Graph.Core/Requests/GraphRequestContext.cs index feacd7d0f4c..bb4c95a2bf5 100644 --- a/src/Microsoft.Graph.Core/Requests/GraphRequestContext.cs +++ b/src/Microsoft.Graph.Core/Requests/GraphRequestContext.cs @@ -31,5 +31,10 @@ public class GraphRequestContext /// A FeatureUsage property /// public FeatureFlag FeatureUsage { get; set; } + + /// + /// A property representing the logged in user + /// + public GraphUserAccount User { get; set; } } } diff --git a/src/Microsoft.Graph.Core/Requests/Middleware/GraphUserAccount.cs b/src/Microsoft.Graph.Core/Requests/Middleware/GraphUserAccount.cs new file mode 100644 index 00000000000..fbc78eef10b --- /dev/null +++ b/src/Microsoft.Graph.Core/Requests/Middleware/GraphUserAccount.cs @@ -0,0 +1,32 @@ +// ------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information. +// ------------------------------------------------------------------------------ + +namespace Microsoft.Graph +{ + /// + /// Class representing the logged in MS graph user + /// + public class GraphUserAccount + { + /// + /// The users email address + /// + public string Email { get; set; } + + /// + /// The identity provider url + /// + public string Environment { get; set; } + + /// + /// Users tenant id + /// + public string TenantId { get; set; } + + /// + /// Users id in a tenant + /// + public string ObjectId { get; set; } + } +} diff --git a/src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthProviderOption.cs b/src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthenticationProviderOption.cs similarity index 100% rename from src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthProviderOption.cs rename to src/Microsoft.Graph.Core/Requests/Middleware/Options/IAuthenticationProviderOption.cs From ad372994c7098f2c4a46f602c451f3edb8a207dc Mon Sep 17 00:00:00 2001 From: Peter Wasonga Ombwa Date: Fri, 22 Feb 2019 16:12:02 -0800 Subject: [PATCH 5/5] Rename IsRetry -> ShouldRetry --- .../Requests/Middleware/RetryHandler.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs b/src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs index aedd03501b9..6cb4911bf0f 100644 --- a/src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs +++ b/src/Microsoft.Graph.Core/Requests/Middleware/RetryHandler.cs @@ -60,7 +60,7 @@ protected async override Task SendAsync(HttpRequestMessage var response = await base.SendAsync(httpRequest, cancellationToken); - if(IsRetry(response) && httpRequest.IsBuffered() && RetryOption.MaxRetry > 0 && RetryOption.ShouldRetry(RetryOption.Delay, 0, response)) + if(ShouldRetry(response) && httpRequest.IsBuffered() && RetryOption.MaxRetry > 0 && RetryOption.ShouldRetry(RetryOption.Delay, 0, response)) { response = await SendRetryAsync(response, cancellationToken); } @@ -95,7 +95,7 @@ private async Task SendRetryAsync(HttpResponseMessage respo // Call base.SendAsync to send the request response = await base.SendAsync(request, cancellationToken); - if (!IsRetry(response) || !request.IsBuffered() || !RetryOption.ShouldRetry(RetryOption.Delay, retryCount, response)) + if (!ShouldRetry(response) || !request.IsBuffered() || !RetryOption.ShouldRetry(RetryOption.Delay, retryCount, response)) { return response; } @@ -133,7 +133,6 @@ private void AddOrUpdateRetryAttempt(HttpRequestMessage request, int retry_count /// The for delay operation. public Task Delay(HttpResponseMessage response, int retry_count, int delay, CancellationToken cancellationToken) { - //TimeSpan delayTimeSpan = TimeSpan.FromMilliseconds(0); HttpHeaders headers = response.Headers; double delayInSeconds = RetryOption.Delay; if (headers.TryGetValues(RETRY_AFTER, out IEnumerable values)) @@ -161,7 +160,7 @@ public Task Delay(HttpResponseMessage response, int retry_count, int delay, Canc /// /// The returned. /// - private bool IsRetry(HttpResponseMessage response) + private bool ShouldRetry(HttpResponseMessage response) { if ((response.StatusCode == HttpStatusCode.ServiceUnavailable || response.StatusCode == (HttpStatusCode)429))