Index: Src/GoogleApis.Tests/Apis/Requests/ClientServiceRequestTest.cs =================================================================== --- a/Src/GoogleApis.Tests/Apis/Requests/ClientServiceRequestTest.cs +++ b/Src/GoogleApis.Tests/Apis/Requests/ClientServiceRequestTest.cs @@ -38,7 +38,7 @@ namespace Google.Apis.Tests.Apis.Requests { - /// Tests for the . + /// Tests for the . [TestFixture] public class ClientServiceRequestTest { @@ -49,7 +49,7 @@ // ApplicationContext.RegisterLogger(new Google.Apis.Logging.Log4NetLogger()); } - /// Helper method to get a string from the stream. + /// Helper method to get a string from the stream. private static string ExtractStringFromStream(Stream stream) { var buffer = new byte[1000]; @@ -57,7 +57,7 @@ return Encoding.UTF8.GetString(buffer, 0, len); } - /// A mock response class. + /// A mock response class. class MockResponse : IDirectResponseSchema { [Newtonsoft.Json.JsonPropertyAttribute("etag")] @@ -81,7 +81,7 @@ } } - /// A mock request class. + /// A mock request class. class MockRequest : IDirectResponseSchema { [Newtonsoft.Json.JsonPropertyAttribute("etag")] @@ -102,10 +102,10 @@ } } - /// A mock service request which returns . + /// A mock service request which returns . class TestClientServiceRequest : ClientServiceRequest { - /// Gets or sets a request number. It's used on concurrent tests. + /// Gets or sets a request number. It's used on concurrent tests. public int CallNum { get; set; } private string httpMethod; private object body; @@ -139,7 +139,7 @@ } } - /// A mock message handler which returns an error. + /// A mock message handler which returns an error. class ErrorMessageHanlder : CountableMessageHandler { public string ExpectedError = @@ -176,22 +176,22 @@ } } - /// Tests message handler which tests the content on the request and the response. - class TestBodyMessageHnalder : CountableMessageHandler + /// Tests message handler which tests the content on the request and the response. + class TestBodyMessageHandler : CountableMessageHandler { - /// Gets or sets indication is GZip is eanbled. + /// Gets or sets indication is GZip is eanbled. public bool GZipEnabled { get; set; } - /// Gets or sets the expected request object. + /// Gets or sets the expected request object. public MockRequest ExpectedRequestObject { get; set; } - /// Gets or sets the returned response object + /// Gets or sets the returned response object public MockResponse ResponseObject { get; set; } - /// Gets or sets the Serializer which is used to serialize and deserialize messages. + /// Gets or sets the Serializer which is used to serialize and deserialize messages. public ISerializer Serializer { get; set; } - /// Gets the thread id in which this handler was invoked. + /// Gets the thread id in which this handler was invoked. public int ThreadId { get; private set; } public string ResponseETag = "\"some-etag-here\""; @@ -203,7 +203,7 @@ var mediaType = "application/json"; string strObject = null; - // if gzip enabled the request content is a gzip stream, otherwise it's a string content + // If gzip enabled the request content is a gzip stream, otherwise it's a string content. if (GZipEnabled) { Assert.That(request.Content, Is.AssignableFrom()); @@ -227,11 +227,11 @@ CharSet = Encoding.UTF8.WebName })); - // deserialize the requested object and check it's equal to the expected object + // Deserialize the requested object and check it's equal to the expected object. var obj = Serializer.Deserialize(strObject); Assert.That(obj, Is.EqualTo(ExpectedRequestObject)); - // return the response (with ETag) + // Return the response (with ETag). var response = new HttpResponseMessage(); var serializedObject = Serializer.Serialize(ResponseObject); response.Content = new StringContent(serializedObject, Encoding.UTF8, mediaType); @@ -240,7 +240,7 @@ } } - /// + /// /// A mock exception which is thrown from a mock message handler in case it is configured to throw exceptions. /// class InvalidOperationMockException : Exception @@ -251,7 +251,7 @@ } } - /// A message handler which returns an Http response message or throw an exception. + /// A message handler which returns a HTTP response message or throw an exception. class MockMessageHandler : CountableMessageHandler { private bool ThrowException { get; set; } @@ -274,13 +274,13 @@ } } - /// A message handler which is used to cancel an Http request in the middle. + /// A message handler which is used to cancel a HTTP request in the middle. class CancelRedirectMessageHandler : CountableMessageHandler { - /// The cancellation token we are going to use to cancel a request. + /// The cancellation token we are going to use to cancel a request. public CancellationTokenSource CancellationTokenSource { get; set; } - /// The request index we are going to cancel. + /// The request index we are going to cancel. public int CancelRequestNum { get; set; } protected override Task SendAsyncCore(HttpRequestMessage request, @@ -303,13 +303,13 @@ } } - /// + /// /// A message handler which checks concurrent calls (each odd request will succeeded, and even request will /// fail on the first try and will succeeded in the second try. /// class ConcurrentCallsHandler : CountableMessageHandler { - /// Gets or sets the Serializer which is used to serialize and deserialize messages. + /// Gets or sets the Serializer which is used to serialize and deserialize messages. public ISerializer Serializer { get; set; } protected override Task SendAsyncCore(HttpRequestMessage request, @@ -335,16 +335,18 @@ return tcs.Task; } - /// Unsuccessful response handler which "handles" service unavailable responses. + /// Unsuccessful response handler which "handles" service unavailable responses. internal class ServiceUnavailableUnsuccessfulResponseHandler : IHttpUnsuccessfulResponseHandler { - public bool HandleResponse(HandleUnsuccessfulResponseArgs args) + public Task HandleResponseAsync(HandleUnsuccessfulResponseArgs args) { - return args.Response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable; + TaskCompletionSource tcs = new TaskCompletionSource(); + tcs.SetResult(args.Response.StatusCode.Equals(HttpStatusCode.ServiceUnavailable)); + return tcs.Task; } } - /// + /// /// Adds service unavailable unsuccessful response handler to the configurable message handler. /// internal class Initializer : IConfigurableHttpClientInitializer @@ -359,7 +361,7 @@ #region Execute (and ExecuteAsync) - /// Tests that canceling a outgoing request to the server works as expected. + /// Tests that canceling a outgoing request to the server works as expected. [Test] public void ExecuteAsync_Cancel() { @@ -399,13 +401,14 @@ { if (ex.InnerException is TaskCanceledException) { - // we expect a task canceled exception in case the canceled request is less or equal total - // number of retries + // We expect a task canceled exception in case the canceled request is less or equal total + // number of retries. Assert.False(cancelRequestNum > service.HttpClient.MessageHandler.NumTries); } else { - // exception should be thrown as a result of casting to MockResponse object + // Canceled exception wasn't thrown, in that case the cancel request number is bigger than + // the actual number of tries. Assert.True(cancelRequestNum > service.HttpClient.MessageHandler.NumTries); } } @@ -415,6 +418,7 @@ } } + /// Tests the execute method in case the service was disposed. [Test] public void Execute_DisposeService() { @@ -435,20 +439,24 @@ Assert.Throws(() => request.Execute()); } - /// A subtest for testing GZip and sync-async calls. + /// A subtest for testing GZip and sync-async calls. + /// Defines if GZip is enabled + /// Defines which method is going to be called (Execute or ExecuteAsync) private void SubtestExecute_GZip(bool gzip, bool async) { - var handler = new TestBodyMessageHnalder() - { - GZipEnabled = gzip, - ResponseObject = new MockResponse { Id = 100, Name = "sample name" }, - ExpectedRequestObject = new MockRequest { Name = "long long name" } - }; + var handler = new TestBodyMessageHandler() + { + GZipEnabled = gzip, + ResponseObject = new MockResponse { Id = 100, Name = "sample name" }, + ExpectedRequestObject = new MockRequest { Name = "long long name" } + }; + var initializer = new BaseClientService.Initializer() - { - GZipEnabled = gzip, - HttpClientFactory = new MockHttpClientFactory(handler) - }; + { + GZipEnabled = gzip, + HttpClientFactory = new MockHttpClientFactory(handler) + }; + using (var service = new MockClientService(initializer)) { handler.Serializer = service.Serializer; @@ -467,61 +475,63 @@ Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, handler.ThreadId); } - // NOTICE: even if GZipEnabled is true, we don't need to extract the real string from the GZip stream, + // Note: Even if GZipEnabled is true, we don't need to extract the real string from the GZip stream, // because in a real request we use HttpClientHandler which its AutomaticDecompression is set to // System.Net.DecompressionMethods.GZip. Assert.That(handler.Calls, Is.EqualTo(1)); - // the returned response should contain ETag, check that the service add the right ETag property on - // the response + // The returned response should contain ETag, check that the service adds the right ETag property on + // the response. handler.ResponseObject.ETag = handler.ResponseETag; Assert.That(response, Is.EqualTo(handler.ResponseObject)); } } - /// Tests execute when GZip is enabled. + /// Tests execute when GZip is enabled. [Test] public void Execute_GZipEnabled() { SubtestExecute_GZip(true, false); } - /// Tests execute when GZip is disabled. + /// Tests execute when GZip is disabled. [Test] public void Execute_GZipDisabled() { SubtestExecute_GZip(false, false); } - /// Tests async execute when GZip is enabled. + /// Tests async execute when GZip is enabled. [Test] public void ExecuteAsync_GZipEnabled() { SubtestExecute_GZip(true, true); } - /// Tests async execute when GZip is disabled. + /// Tests async execute when GZip is disabled. [Test] public void ExecuteAsync_GZipDisabled() { SubtestExecute_GZip(false, true); } - /// Tests execute with unicode characters. + /// Tests execute with unicode characters. [Test] public void Execute_UnicodeCharacters() { - var handler = new TestBodyMessageHnalder() - { - GZipEnabled = false, - ResponseObject = new MockResponse { Id = 100, Name = @"مرحبا العالم" }, - ExpectedRequestObject = new MockRequest { Name = @"مرحبا العالم! 您好,世界!" } - }; + var handler = new TestBodyMessageHandler() + { + GZipEnabled = false, + ResponseObject = new MockResponse { Id = 100, Name = @"مرحبا العالم" }, + ExpectedRequestObject = new MockRequest { Name = @"مرحبا العالم! 您好,世界!" } + }; + var initializer = new BaseClientService.Initializer() - { - GZipEnabled = false, - HttpClientFactory = new MockHttpClientFactory(handler) - }; + { + GZipEnabled = false, + HttpClientFactory = new MockHttpClientFactory(handler) + }; + using (var service = new MockClientService(initializer)) { handler.Serializer = service.Serializer; @@ -529,17 +539,17 @@ var request = new TestClientServiceRequest(service, "GET", handler.ExpectedRequestObject); var response = request.Execute(); Assert.That(handler.Calls, Is.EqualTo(1)); - // the returned response should contain ETag, check that the service add the right ETag property on - // the response + // The returned response should contain ETag, check that the service add the right ETag property on + // the response. handler.ResponseObject.ETag = handler.ResponseETag; Assert.That(response, Is.EqualTo(handler.ResponseObject)); } } - /// - /// A subtest for testing execute when an exception is thrown during sending the request, with or without - /// back-off. If back-off handler is attached to the service's message handler, there are going to be 3 tries - /// (3 is the default value of ) before the operation + /// + /// A subtest for testing Execute when an exception is thrown while sending the request. This is tested with + /// and without back-off. If back-off handler is attached to the service's message handler, there should be 3 + /// tries (the default value of ) before the operation /// fails. /// /// Indicates if back-off handler is attached to the service. @@ -547,14 +557,13 @@ { var handler = new MockMessageHandler(true); var initializer = new BaseClientService.Initializer() - { - HttpClientFactory = new MockHttpClientFactory(handler) - }; + { + HttpClientFactory = new MockHttpClientFactory(handler) + }; - // sets the default exponential back-off policy by the input + // Set the default exponential back-off policy by the input. initializer.DefaultExponentialBackOffPolicy = backOff ? - BaseClientService.ExponentialBackOffPolicy.Exception : - BaseClientService.ExponentialBackOffPolicy.None; + ExponentialBackOffPolicy.Exception : ExponentialBackOffPolicy.None; using (var service = new MockClientService(initializer)) { @@ -566,7 +575,7 @@ } } - /// + /// /// Tests execute when an exception is thrown during a request and exponential back-off is enabled. /// [Test] @@ -575,7 +584,7 @@ SubtestExecute_ThrowException(true); } - /// + /// /// Tests execute when an exception is thrown during a request and exponential back-off is disabled. /// [Test] @@ -584,10 +593,10 @@ SubtestExecute_ThrowException(false); } - /// - /// A subtest for testing async execute when an exception is thrown during sending the request, with or without - /// back-off handler. If back-off handler is attached to the service's message handler, there are going to be 3 - /// tries (3 is the default value of ) before the + /// + /// A subtest for testing ExecuteAsync when an exception is thrown while sending the request. This is tested + /// with and without back-off. If back-off handler is attached to the service's message handler, there should + /// be 3 tries (the default value of ) before the /// operation fails. /// /// Indicates if back-off handler is attached to the service. @@ -599,10 +608,9 @@ HttpClientFactory = new MockHttpClientFactory(handler) }; - // configure the back-off behavior by the input + // Configure the back-off behavior by the input. initializer.DefaultExponentialBackOffPolicy = backOff ? - BaseClientService.ExponentialBackOffPolicy.Exception : - BaseClientService.ExponentialBackOffPolicy.None; + ExponentialBackOffPolicy.Exception : ExponentialBackOffPolicy.None; using (var service = new MockClientService(initializer)) { @@ -623,7 +631,7 @@ } } - /// + /// /// Tests async execute when an exception is thrown during a request and exponential back-off is enabled. /// [Test] @@ -632,7 +640,7 @@ SubtestExecuteAsync_ThrowException(true); } - /// + /// /// Tests async execute when an exception is thrown during a request and exponential back-off is disabled. /// [Test] @@ -641,15 +649,16 @@ SubtestExecuteAsync_ThrowException(false); } - /// Tests execute when server returned an error. + /// Tests execute when server returned an error. [Test] public void Execute_Error() { var handler = new ErrorMessageHanlder(); var initializer = new BaseClientService.Initializer() - { - HttpClientFactory = new MockHttpClientFactory(handler) - }; + { + HttpClientFactory = new MockHttpClientFactory(handler) + }; + using (var service = new MockClientService(initializer)) { var request = new TestClientServiceRequest(service, "GET", null); @@ -666,15 +675,16 @@ } } - /// Tests execute when server returned an error. + /// Tests execute when server returned an error. [Test] public void ExecuteAsync_Error() { var handler = new ErrorMessageHanlder(); var initializer = new BaseClientService.Initializer - { - HttpClientFactory = new MockHttpClientFactory(handler) - }; + { + HttpClientFactory = new MockHttpClientFactory(handler) + }; + using (var service = new MockClientService(initializer)) { var request = new TestClientServiceRequest(service, "GET", null); @@ -698,17 +708,17 @@ } } - /// Tests async execution of multiple request simultaneously. + /// Tests async execution of multiple request simultaneously. [Test] public void ExecuteAsync_Simultaneously() { var tasks = new List>(); var handler = new ConcurrentCallsHandler(); var initializer = new BaseClientService.Initializer() - { - HttpClientFactory = new MockHttpClientFactory(handler), - HttpClientInitializer = new ConcurrentCallsHandler.Initializer() - }; + { + HttpClientFactory = new MockHttpClientFactory(handler), + HttpClientInitializer = new ConcurrentCallsHandler.Initializer() + }; using (var service = new MockClientService(initializer)) { @@ -746,20 +756,22 @@ #region ExecuteStream (and ExecuteAsStreamAsync) - /// A subtest for testing execute as stream (async and sync). + /// A subtest for testing execute as stream (async and sync). private void SubtestExecuteAsStream(bool async) { - var handler = new TestBodyMessageHnalder - { - GZipEnabled = false, - ResponseObject = new MockResponse { Id = 100, Name = "sample name" }, - ExpectedRequestObject = new MockRequest { Name = "long long name" } - }; + var handler = new TestBodyMessageHandler + { + GZipEnabled = false, + ResponseObject = new MockResponse { Id = 100, Name = "sample name" }, + ExpectedRequestObject = new MockRequest { Name = "long long name" } + }; + var initializer = new BaseClientService.Initializer - { - GZipEnabled = false, - HttpClientFactory = new MockHttpClientFactory(handler) - }; + { + GZipEnabled = false, + HttpClientFactory = new MockHttpClientFactory(handler) + }; + using (var service = new MockClientService(initializer)) { handler.Serializer = service.Serializer; @@ -782,7 +794,7 @@ Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, handler.ThreadId); } - // read the object + // Read the object. var str = ExtractStringFromStream(stream); response = service.Serializer.Deserialize(str); @@ -791,14 +803,14 @@ } } - /// Tests execute stream. + /// Tests execute stream. [Test] public void ExecuteAsStream() { SubtestExecuteAsStream(false); } - /// Tests execute stream (async). + /// Tests execute stream (async). [Test] public void ExecuteAsStreamAsync() { @@ -811,7 +823,7 @@ #region Query Parameters - /// Client request which contains query parameters. + /// Client request which contains query parameters. class ClientServiceRequestWithQueryParameters : TestClientServiceRequest { [RequestParameterAttribute("required", Google.Apis.Util.RequestParameterType.Query)] @@ -836,50 +848,50 @@ : base(service, method, body) { RequestParameters.Add("required", new Parameter - { - Name = "required", - IsRequired = true, - ParameterType = "query" - }); + { + Name = "required", + IsRequired = true, + ParameterType = "query" + }); RequestParameters.Add("optionalWithValue", new Parameter - { - Name = "optionalWithValue", - IsRequired = false, - ParameterType = "query", - DefaultValue = "DoesNotDisplay" - }); + { + Name = "optionalWithValue", + IsRequired = false, + ParameterType = "query", + DefaultValue = "DoesNotDisplay" + }); RequestParameters.Add("optionalWithValue2", new Parameter - { - Name = "optionalWithValue", - IsRequired = false, - ParameterType = "query", - DefaultValue = "DoesNotDisplay" - }); + { + Name = "optionalWithValue", + IsRequired = false, + ParameterType = "query", + DefaultValue = "DoesNotDisplay" + }); RequestParameters.Add("optionalWithNull", new Parameter - { - Name = "optionalWithNull", - IsRequired = false, - ParameterType = "query", - DefaultValue = "c" - }); + { + Name = "optionalWithNull", + IsRequired = false, + ParameterType = "query", + DefaultValue = "c" + }); RequestParameters.Add("optionalEmpty", new Parameter - { - Name = "optionalEmpty", - IsRequired = false, - ParameterType = "query", - DefaultValue = "d" - }); + { + Name = "optionalEmpty", + IsRequired = false, + ParameterType = "query", + DefaultValue = "d" + }); RequestParameters.Add("optionalNotPressent", new Parameter - { - Name = "optionalNotPressent", - IsRequired = false, - ParameterType = "query", - DefaultValue = "DoesNotDisplay" - }); + { + Name = "optionalNotPressent", + IsRequired = false, + ParameterType = "query", + DefaultValue = "DoesNotDisplay" + }); } } - /// Tests build request with query parameters. + /// Tests build request with query parameters. [Test] public void CreateRequest_QueryParameters() { @@ -897,7 +909,7 @@ } } - /// Tests build request with missing required query parameter. + /// Tests build request with missing required query parameter. [Test] public void CreateRequest_QueryParameterIsMissing() { @@ -922,7 +934,7 @@ #region Path Parameters - /// Client request which contains path parameters. + /// Client request which contains path parameters. class ClientServiceRequestWithPathParameters : TestClientServiceRequest { [RequestParameter("path1", RequestParameterType.Path)] @@ -954,7 +966,7 @@ } } - /// Tests build request with path parameters. + /// Tests build request with path parameters. [Test] public void CreateRequest_PathParameters() { @@ -977,14 +989,15 @@ private const string SimpleDeveloperKey = "ABC123"; private const string ComplexDeveloperKey = "?&^% ABC123"; - /// Tests build request with simple developer key. + /// Tests build request with simple developer key. [Test] public void CreateRequest_DeveloperKey() { var initializer = new BaseClientService.Initializer - { - ApiKey = SimpleDeveloperKey - }; + { + ApiKey = SimpleDeveloperKey + }; + using (var service = new MockClientService(initializer, "https://build_request_params")) { var request = new TestClientServiceRequest(service, "GET", null); @@ -994,14 +1007,15 @@ } } - /// Tests build request with complex developer key. + /// Tests build request with complex developer key. [Test] public void CreateRequest_DeveloperKey_RequiresEscape() { var initializer = new BaseClientService.Initializer - { - ApiKey = ComplexDeveloperKey - }; + { + ApiKey = ComplexDeveloperKey + }; + using (var service = new MockClientService(initializer, "https://build_request_params")) { var request = new TestClientServiceRequest(service, "GET", null); @@ -1017,7 +1031,7 @@ #region Supported Methods - /// Tests if invalid method throws an exception. + /// Tests if invalid method throws an exception. [Test] public void CreateRequest_UnsupportedMethods() { @@ -1028,7 +1042,7 @@ } } - /// Tests that valid method doesn't throw an exception. + /// Tests that valid method doesn't throw an exception. [Test] public void CreateRequest_SupportedMethods() { @@ -1052,20 +1066,20 @@ #region ETag - /// Tests the create request method with different ETags. + /// Tests the create request method with different ETags. [Test] public void CreateRequest_ETag() { var body = new MockRequest { Name = "long long name" }; using (var service = new MockClientService()) { - // no ETag (ETag = null) + // No ETag (ETag = null). var request = new TestClientServiceRequest(service, HttpConsts.Get, body); var httpRequest = request.CreateRequest(); Assert.That(httpRequest.Headers.IfMatch.Count, Is.EqualTo(0)); Assert.That(httpRequest.Headers.IfNoneMatch.Count, Is.EqualTo(0)); - // ETag has a value, but ETag action is ignored + // ETag has a value, but ETag action is ignored. body.ETag = "\"ETAG_HERE\""; request = new TestClientServiceRequest(service, HttpConsts.Get, body); request.ETagAction = ETagAction.Ignore; @@ -1073,21 +1087,21 @@ Assert.That(httpRequest.Headers.IfMatch.Count, Is.EqualTo(0)); Assert.That(httpRequest.Headers.IfNoneMatch.Count, Is.EqualTo(0)); - // ETag has a value, so use default action (Get -> If-None-Match) + // ETag has a value, so use default action (Get -> If-None-Match). request = new TestClientServiceRequest(service, HttpConsts.Get, body); httpRequest = request.CreateRequest(); Assert.That(httpRequest.Headers.IfMatch.Count, Is.EqualTo(0)); Assert.That(httpRequest.Headers.IfNoneMatch.Count, Is.EqualTo(1)); Assert.That(httpRequest.Headers.IfNoneMatch.First(), Is.EqualTo(new EntityTagHeaderValue(body.ETag))); - // ETag has a value, so use default action (Post -> If-Match) + // ETag has a value, so use default action (Post -> If-Match). request = new TestClientServiceRequest(service, HttpConsts.Post, body); httpRequest = request.CreateRequest(); Assert.That(httpRequest.Headers.IfNoneMatch.Count, Is.EqualTo(0)); Assert.That(httpRequest.Headers.IfMatch.Count, Is.EqualTo(1)); Assert.That(httpRequest.Headers.IfMatch.First(), Is.EqualTo(new EntityTagHeaderValue(body.ETag))); - // ETag has a value, default is override, use the specified ETag action + // ETag has a value, default is override, use the specified ETag action. request = new TestClientServiceRequest(service, HttpConsts.Post, body); request.ETagAction = ETagAction.IfNoneMatch; httpRequest = request.CreateRequest(); @@ -1095,7 +1109,7 @@ Assert.That(httpRequest.Headers.IfNoneMatch.Count, Is.EqualTo(1)); Assert.That(httpRequest.Headers.IfNoneMatch.First(), Is.EqualTo(new EntityTagHeaderValue(body.ETag))); - // ETag has a value, default is override, use the specified ETag action + // ETag has a value, default is override, use the specified ETag action. request = new TestClientServiceRequest(service, HttpConsts.Get, body); request.ETagAction = ETagAction.IfMatch; httpRequest = request.CreateRequest(); @@ -1105,7 +1119,7 @@ } } - /// Tests that get default ETag action works as expected. + /// Tests that get default ETag action works as expected. [Test] public void GetDefaultETagActionTest() {