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(); } }
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)); } }
/// <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()); }
/// <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)); } }
/// <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)); } }