public void Execute_UnicodeCharacters()
        {
            var handler = new TestBodyMessageHnalder()
            {
                GZipEnabled    = false,
                ResponseObject = new MockResponse {
                    Id = 100, Name = @"مرحبا العالم"
                },
                ExpectedRequestObject = new MockRequest {
                    Name = @"مرحبا العالم! 您好,世界!"
                }
            };
            var initializer = new BaseClientService.Initializer()
            {
                GZipEnabled       = false,
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer))
            {
                handler.Serializer = service.Serializer;

                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
                handler.ResponseObject.ETag = handler.ResponseETag;
                Assert.That(response, Is.EqualTo(handler.ResponseObject));
            }
        }
        /// <summary>
        /// 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 several
        /// retries (up to 2 minutes).
        /// </summary>
        /// <param name="backOff">Indicates if back-off handler is attached to the service.</param>
        private void SubtestExecute_ThrowException(bool backOff)
        {
            var handler     = new MockMessageHandler(true);
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            // by default back-off is used, so disable it in case backOff is false
            if (!backOff)
            {
                initializer.DefaultExponentialBackOffPolicy = BaseClientService.ExponentialBackOffPolicy.None;
            }

            using (var service = new MockClientService(initializer))
            {
                var request = new TestClientServiceRequest(service, "GET", null);
                Assert.Throws <InvalidOperationMockException>(() => request.Execute());

                // if back-off is enabled, we use 2 minutes maximum wait time for a request, so we should make lg(120)
                // + 1 calls
                int calls = backOff ? (int)Math.Ceiling(Math.Log(120, 2) + 1) : 1;
                Assert.That(handler.Calls, Is.EqualTo(calls));
            }
        }
        public void CreateOuterRequestContent_Test()
        {
            using (var service = new MockClientService("http://sample.com"))
            {
                var request1 = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"100\"",
                    Name = "Name1"
                });
                var request2 = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"200\"",
                    Name = "Name1-1"
                });

                var content    = BatchRequest.CreateOuterRequestContent(new[] { request1, request2 }).Result;
                var requestStr = content.ReadAsStringAsync().Result;

                // Read the boundary.
                string boundary = null;
                using (var reader = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(requestStr))))
                {
                    var line = reader.ReadLine();
                    boundary = line.Substring(2);
                }

                Assert.Equal(ExpectedContentMessage.Replace("BOUNDARY", boundary), NormalizeLineEndings(requestStr));
            }
        }
        public void ExecuteAsync_NoCallback_Test()
        {
            var handler     = new BatchMessageHandler(true);
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer, "http://sample.com"))
            {
                var responses = new List <Tuple <MockResponse, RequestError, HttpResponseMessage> >();
                var batch     = new BatchRequest(service);
                var request1  = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"100\"",
                    Name = "Name1"
                });
                var request2 = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"200\"",
                    Name = "Name1-1"
                });
                batch.Queue <MockResponse>(request1, null);
                batch.Queue <MockResponse>(request2, null);
                batch.ExecuteAsync().Wait();
            }
        }
Пример #5
0
        public void ExecuteAsync_Error()
        {
            var handler     = new ErrorMessageHanlder();
            var initializer = new BaseClientService.Initializer
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer))
            {
                var            request    = new TestClientServiceRequest(service, "GET", null);
                AutoResetEvent resetEvent = new AutoResetEvent(false);
                var            task       = request.ExecuteAsync();
                var            error      = string.Empty;
                task.ContinueWith(t =>
                {
                    // should not ENTER this code, the task should fail
                    resetEvent.Set();
                }, TaskContinuationOptions.OnlyOnRanToCompletion);
                task.ContinueWith(t =>
                {
                    // catch the error
                    error = t.Exception.InnerException.ToString();
                    resetEvent.Set();
                }, TaskContinuationOptions.NotOnRanToCompletion);
                resetEvent.WaitOne();
                Assert.True(error.Contains(handler.ExpectedError), "Error message is invalid");
                Assert.That(handler.Calls, Is.EqualTo(1));
            }
        }
Пример #6
0
        /// <summary>
        /// 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 <seealso cref="ConfigurableMessageHandler.NumTries"/>) before the
        /// operation fails.
        /// </summary>
        /// <param name="backOff">Indicates if back-off handler is attached to the service.</param>
        private void SubtestExecuteAsync_ThrowException(bool backOff)
        {
            var handler     = new MockMessageHandler(true);
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            // Configure the back-off behavior by the input.
            initializer.DefaultExponentialBackOffPolicy = backOff ?
                                                          ExponentialBackOffPolicy.Exception : ExponentialBackOffPolicy.None;

            using (var service = new MockClientService(initializer))
            {
                var request = new TestClientServiceRequest(service, "GET", null);
                var task    = request.ExecuteAsync();
                try
                {
                    var result = task.Result;
                    Assert.Fail("Exception should be thrown");
                }
                catch (AggregateException ex)
                {
                    Assert.That(ex.InnerException, Is.AssignableFrom(typeof(InvalidOperationMockException)));
                }

                int calls = backOff ? service.HttpClient.MessageHandler.NumTries : 1;
                Assert.That(handler.Calls, Is.EqualTo(calls));
            }
        }
 private void SubtestCreateRequest_SupportedMethod(string method)
 {
     using (var service = new MockClientService("https://build_request_params"))
     {
         var request     = new TestClientServiceRequest(service, method, null);
         var httpRequest = request.CreateRequest();
     }
 }
 public void CreateRequest_UnsupportedMethods()
 {
     using (var service = new MockClientService("https://build_request_params"))
     {
         var request = new TestClientServiceRequest(service, "Unsupported", null);
         Assert.Throws <ArgumentOutOfRangeException>(() => request.CreateRequest());
     }
 }
        public void CreateRequest_ETag()
        {
            var body = new MockRequest {
                Name = "long long name"
            };

            using (var service = new MockClientService())
            {
                // 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
                body.ETag          = "\"ETAG_HERE\"";
                request            = new TestClientServiceRequest(service, HttpConsts.Get, body);
                request.ETagAction = ETagAction.Ignore;
                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, 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)
                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
                request            = new TestClientServiceRequest(service, HttpConsts.Post, body);
                request.ETagAction = ETagAction.IfNoneMatch;
                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, default is override, use the specified ETag action
                request            = new TestClientServiceRequest(service, HttpConsts.Get, body);
                request.ETagAction = ETagAction.IfMatch;
                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)));
            }
        }
        public void CreateRequest_DeveloperKey_RequiresEscape()
        {
            var initializer = new BaseClientService.Initializer
            {
                ApiKey = ComplexDeveloperKey
            };

            using (var service = new MockClientService(initializer, "https://build_request_params"))
            {
                var request     = new TestClientServiceRequest(service, "GET", null);
                var httpRequest = request.CreateRequest();
                Assert.That(httpRequest.RequestUri, Is.EqualTo(new Uri(
                                                                   "https://build_request_params/restPath0?key=%3F%26%5E%25%20%20ABC123")));
            }
        }
        public void CreateRequest_DeveloperKey()
        {
            var initializer = new BaseClientService.Initializer
            {
                ApiKey = SimpleDeveloperKey
            };

            using (var service = new MockClientService(initializer, "https://build_request_params"))
            {
                var request     = new TestClientServiceRequest(service, "GET", null);
                var httpRequest = request.CreateRequest();
                Assert.That(httpRequest.RequestUri, Is.EqualTo(new Uri(
                                                                   "https://build_request_params/restPath0?key=" + SimpleDeveloperKey)));
            }
        }
        /// <summary> A subtest for testing execute as stream (async and sync). </summary>
        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 initializer = new BaseClientService.Initializer
            {
                GZipEnabled       = false,
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer))
            {
                handler.Serializer = service.Serializer;

                var request = new TestClientServiceRequest(service, "GET", handler.ExpectedRequestObject);

                MockResponse response = null;
                Stream       stream   = null;
                if (async)
                {
                    request.ExecuteAsStreamAsync().ContinueWith(t =>
                    {
                        stream = t.Result;
                    }, TaskContinuationOptions.OnlyOnRanToCompletion).Wait();
                    Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, handler.ThreadId);
                }
                else
                {
                    stream = request.ExecuteAsStream();
                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, handler.ThreadId);
                }

                // read the object
                var str = ExtractStringFromStream(stream);
                response = service.Serializer.Deserialize <MockResponse>(str);

                Assert.That(handler.Calls, Is.EqualTo(1));
                Assert.That(response, Is.EqualTo(handler.ResponseObject));
            }
        }
        /// <summary> A subtest for testing GZip and sync-async calls. </summary>
        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 initializer = new BaseClientService.Initializer()
            {
                GZipEnabled       = gzip,
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer))
            {
                handler.Serializer = service.Serializer;

                var          request  = new TestClientServiceRequest(service, "POST", handler.ExpectedRequestObject);
                MockResponse response = null;
                if (async)
                {
                    var task = request.ExecuteAsync();
                    response = task.Result;
                    Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, handler.ThreadId);
                }
                else
                {
                    response = request.Execute();
                    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,
                // 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
                handler.ResponseObject.ETag = handler.ResponseETag;
                Assert.That(response, Is.EqualTo(handler.ResponseObject));
            }
        }
        public void ExecuteAsync_Simultaneously()
        {
            var tasks       = new List <Task <MockResponse> >();
            var handler     = new ConcurrentCallsHandler();
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory     = new MockHttpClientFactory(handler),
                HttpClientInitializer = new ConcurrentCallsHandler.Initializer()
            };

            using (var service = new MockClientService(initializer))
            {
                int calls = 100;
                handler.Serializer = service.Serializer;

                CountdownEvent ce = new CountdownEvent(calls);
                foreach (var i in Enumerable.Range(1, calls))
                {
                    var request = new TestClientServiceRequest(service, "GET", null)
                    {
                        CallNum = i
                    };
                    var task = request.ExecuteAsync();
                    task.ContinueWith(c => ce.Signal());
                    tasks.Add(task);
                }
                ce.Wait();

                for (var i = 1; i <= tasks.Count; ++i)
                {
                    var response = tasks[i - 1].Result;

                    // check that we got the right response. Name should be equal to the index number modulo 10 (or
                    // index number plus one module 10, if it's an even request - because even request should fail in
                    // the first request, but should succeed in the next try). That's the logic of our
                    // ConcurrentCallHandler, see it core SendAsyncCore method to understand better the logic
                    var nameIndex = ((i % 2 == 0) ? i + 1 : i) % 10;
                    Assert.That(response.Name, Is.EqualTo("Name-" + nameIndex));
                }

                // half of the request should succeed in the second call, so total calls should be calls + calls/2
                Assert.That(handler.Calls, Is.EqualTo(calls + calls / 2));
            }
        }
        public void Execute_DisposeService()
        {
            var handler     = new MockMessageHandler();
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            TestClientServiceRequest request;

            using (var service = new MockClientService(initializer))
            {
                request = new TestClientServiceRequest(service, "POST", new MockRequest());
            }

            // the service was disposed before the request was made (and the message handler as well). As a result an
            // exception should be thrown before we try to send the request
            Assert.Throws <ObjectDisposedException>(() => request.Execute());
        }
Пример #16
0
        /// <summary>
        /// Test helper to test canceling token in a middle of a request to the server
        /// </summary>
        /// <param name="cancelRequestNum">
        /// The index of the "server"'s request which a cancel token will be mimic.
        /// </param>
        private void SubtestExecuteAsync_Cancel(int cancelRequestNum)
        {
            var handler = new CancelRedirectMessageHandler();

            handler.CancellationTokenSource = new CancellationTokenSource();
            handler.CancelRequestNum        = cancelRequestNum;

            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            TestClientServiceRequest request;

            using (var service = new MockClientService(initializer))
            {
                request = new TestClientServiceRequest(service, "POST", new MockRequest());
                try
                {
                    request.ExecuteAsync(handler.CancellationTokenSource.Token).Wait();
                    Assert.Fail();
                }
                catch (AggregateException ex)
                {
                    if (ex.InnerException is TaskCanceledException)
                    {
                        // 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.NumRedirects + 1);
                    }
                    else
                    {
                        // 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 + 1);
                    }
                }

                var expectedCalls = Math.Min(service.HttpClient.MessageHandler.NumRedirects + 1, cancelRequestNum);
                Assert.That(handler.Calls, Is.EqualTo(expectedCalls));
            }
        }
Пример #17
0
        /// <summary>
        /// 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 <seealso cref="ConfigurableMessageHandler.NumTries"/>) before the operation
        /// fails.
        /// </summary>
        /// <param name="backOff">Indicates if back-off handler is attached to the service.</param>
        private void SubtestExecute_ThrowException(bool backOff)
        {
            var handler     = new MockMessageHandler(true);
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            // Set the default exponential back-off policy by the input.
            initializer.DefaultExponentialBackOffPolicy = backOff ?
                                                          ExponentialBackOffPolicy.Exception : ExponentialBackOffPolicy.None;

            using (var service = new MockClientService(initializer))
            {
                var request = new TestClientServiceRequest(service, "GET", null);
                Assert.Throws <InvalidOperationMockException>(() => request.Execute());

                int calls = backOff ? service.HttpClient.MessageHandler.NumTries : 1;
                Assert.That(handler.Calls, Is.EqualTo(calls));
            }
        }
        public void CreateIndividualRequest_Test()
        {
            var expectedMessage = @"POST http://sample.com/5?q=20
If-Match: ""123""
Content-Type: application/json; charset=utf-8
Content-Length:  40

{""etag_key"":""\""123\"""",""name_key"":""Name""}
";

            using (var service = new MockClientService("http://sample.com"))
            {
                var request = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"123\"",
                    Name = "Name"
                });
                var content    = BatchRequest.CreateIndividualRequest(request).Result;
                var requestStr = content.ReadAsStringAsync().Result;
                Assert.AreEqual(expectedMessage, requestStr);
            }
        }
        public void Execute_Error()
        {
            var handler     = new ErrorMessageHanlder();
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer))
            {
                var request = new TestClientServiceRequest(service, "GET", null);
                try
                {
                    request.Execute();
                    Assert.Fail();
                }
                catch (Exception ex)
                {
                    Assert.True(ex.Message.Contains(handler.ExpectedError), "Error message is invalid");
                }
                Assert.That(handler.Calls, Is.EqualTo(1));
            }
        }
        /// <summary>Subtest for the execute method.</summary>
        /// <param name="successful2ndReponse">Indicates if the 2nd individual response is unsuccessful.</param>
        void SubtestExecuteAsync_Test(bool successful2ndReponse)
        {
            var handler     = new BatchMessageHandler(successful2ndReponse);
            var initializer = new BaseClientService.Initializer()
            {
                HttpClientFactory = new MockHttpClientFactory(handler)
            };

            using (var service = new MockClientService(initializer, "http://sample.com"))
            {
                var responses = new List <Tuple <MockResponse, RequestError, HttpResponseMessage> >();
                var batch     = new BatchRequest(service);
                var request1  = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"100\"",
                    Name = "Name1"
                });
                var request2 = new TestClientServiceRequest(service, new MockRequest
                {
                    ETag = "\"200\"",
                    Name = "Name1-1"
                });
                // Adding the content, error and message into the responses list to verify the results later on
                batch.Queue <MockResponse>(request1, (content, error, index, message) =>
                {
                    responses.Add(new Tuple <MockResponse, RequestError, HttpResponseMessage>(
                                      content, error, message));
                });
                batch.Queue <MockResponse>(request2, (content, error, index, message) =>
                {
                    responses.Add(new Tuple <MockResponse, RequestError, HttpResponseMessage>(
                                      content, error, message));
                });
                batch.ExecuteAsync().Wait();

                Assert.That(responses.Count, Is.EqualTo(2));
                var tuple = responses[0];
                Assert.Null(tuple.Item2);   // no error
                var response = tuple.Item1; // response
                Assert.That(response.ETag, Is.EqualTo(@"""10011"""));
                Assert.That(response.Id, Is.EqualTo(1));
                var httpMessage = tuple.Item3; // HTTP message
                Assert.That(httpMessage.Content.Headers.ContentType.MediaType, Is.EqualTo("application/json"));
                Assert.That(httpMessage.Content.Headers.ContentLength, Is.EqualTo(505));

                tuple = responses[1];
                if (successful2ndReponse)
                {
                    Assert.Null(tuple.Item2); // no error
                    response = tuple.Item1;   // response
                    Assert.That(response.ETag, Is.EqualTo(@"""234"""));
                    Assert.That(response.Id, Is.EqualTo(2));
                }
                else
                {
                    Assert.Null(tuple.Item1);            // no response
                    RequestError reqError = tuple.Item2; // error
                    Assert.That(reqError.Errors.Count, Is.EqualTo(1));
                    Assert.That(reqError.Code, Is.EqualTo(404));
                    Assert.That(reqError.Message, Is.EqualTo("Not Found"));
                }
                httpMessage = tuple.Item3; // HTTP message
                Assert.That(httpMessage.Content.Headers.ContentType.MediaType, Is.EqualTo("application/json"));
                Assert.That(httpMessage.Content.Headers.ContentLength, Is.EqualTo(202));
            }
        }