public static async Task Intercept_Http_Get_For_Raw_Bytes() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("files.domain.com") .ForPath("setup.exe") .WithMediaType("application/octet-stream") .WithContent(() => new byte[] { 0, 1, 2, 3, 4 }); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); // Act byte[] content = await client.GetByteArrayAsync("https://files.domain.com/setup.exe"); // Assert content.ShouldBe(new byte[] { 0, 1, 2, 3, 4 }); }
public static async Task Use_With_Refit() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/justeat") .WithJsonContent(new { id = 1516790, login = "******", url = "https://api.github.com/orgs/justeat" }); var options = new HttpClientInterceptorOptions().Register(builder); var service = RestService.For <IGitHub>(options.CreateHttpClient("https://api.github.com")); // Act Organization actual = await service.GetOrganizationAsync("justeat"); // Assert actual.ShouldNotBeNull(); actual.Id.ShouldBe("1516790"); actual.Login.ShouldBe("justeat"); actual.Url.ShouldBe("https://api.github.com/orgs/justeat"); }
public static async Task Intercept_Http_Get_For_Json_Object_Using_System_Text_Json() { // Arrange var options = new HttpClientInterceptorOptions(); var builder = new HttpRequestInterceptionBuilder(); builder.Requests().ForGet().ForHttps().ForHost("public.je-apis.com").ForPath("terms") .Responds().WithJsonContent(new { Id = 1, Link = "https://www.just-eat.co.uk/privacy-policy" }) .RegisterWith(options); using var client = options.CreateHttpClient(); // Act using var utf8Json = await client.GetStreamAsync("https://public.je-apis.com/terms"); // Assert using var content = await JsonDocument.ParseAsync(utf8Json); content.RootElement.GetProperty("Id").GetInt32().ShouldBe(1); content.RootElement.GetProperty("Link").GetString().ShouldBe("https://www.just-eat.co.uk/privacy-policy"); }
/// <summary> /// Registers one or more HTTP request interceptions, replacing any existing registrations. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="collection">A collection of <see cref="HttpRequestInterceptionBuilder"/> instances to use to create the registration(s).</param> /// <returns> /// The current <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="collection"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions Register( this HttpClientInterceptorOptions options, IEnumerable <HttpRequestInterceptionBuilder> collection) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (collection == null) { throw new ArgumentNullException(nameof(collection)); } foreach (var builder in collection) { options.Register(builder); } return(options); }
public static async Task SendAsync_Throws_If_Registration_Missing_Post() { // Arrange var options = new HttpClientInterceptorOptions() .ThrowsOnMissingRegistration(); var mock = new Mock <HttpMessageHandler>(); using var handler = options.CreateHttpMessageHandler(); using var target = new HttpClient(handler); using var content = new StringContent(string.Empty); // Act var exception = await Assert.ThrowsAsync <HttpRequestNotInterceptedException>( () => target.PostAsync("https://google.com/", content)); // Assert exception.Message.ShouldBe("No HTTP response is configured for POST https://google.com/."); exception.Request.ShouldNotBeNull(); exception.Request.RequestUri.ShouldBe(new Uri("https://google.com/")); }
public static async Task Intercept_Http_Get_For_Html_String() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForHost("www.google.co.uk") .ForPath("search") .ForQuery("q=Just+Eat") .WithMediaType("text/html") .WithContent(@"<!DOCTYPE html><html dir=""ltr"" lang=""en""><head><title>Just Eat</title></head></html>"); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); // Act string html = await client.GetStringAsync("http://www.google.co.uk/search?q=Just+Eat"); // Assert html.ShouldContain("Just Eat"); }
public static async Task GetResponseAsync_Uses_Version() { // Arrange string url = "https://google.com/"; var builder = new HttpRequestInterceptionBuilder() .ForUrl(url) .WithVersion(new Version(2, 1)); var options = new HttpClientInterceptorOptions() .Register(builder); var request = new HttpRequestMessage(HttpMethod.Get, url); // Act HttpResponseMessage actual = await options.GetResponseAsync(request); // Assert actual.ShouldNotBeNull(); actual.Version.ShouldBe(new Version(2, 1)); }
public static async Task Intercept_Http_Get_For_Json_Object() { // Arrange var options = new HttpClientInterceptorOptions(); var builder = new HttpRequestInterceptionBuilder(); builder.Requests().ForGet().ForHttps().ForHost("public.je-apis.com").ForPath("terms") .Responds().WithJsonContent(new { Id = 1, Link = "https://www.just-eat.co.uk/privacy-policy" }) .RegisterWith(options); using var client = options.CreateHttpClient(); // Act string json = await client.GetStringAsync("https://public.je-apis.com/terms"); // Assert var content = JObject.Parse(json); content.Value <int>("Id").ShouldBe(1); content.Value <string>("Link").ShouldBe("https://www.just-eat.co.uk/privacy-policy"); }
public static async Task Intercept_Http_Delete() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForDelete() .ForHttps() .ForHost("public.je-apis.com") .ForPath("baskets/123/orderitems/456") .WithStatus(HttpStatusCode.NoContent); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); // Act using var response = await client.DeleteAsync("https://public.je-apis.com/baskets/123/orderitems/456"); // Assert response.StatusCode.ShouldBe(HttpStatusCode.NoContent); }
public static async Task GetResponseAsync_Returns_Empty_Response_If_ContentStream_Returns_Null_Asynchronous() { // Arrange var method = HttpMethod.Get; var uri = new Uri("https://google.com/"); var options = new HttpClientInterceptorOptions() .RegisterStream(method, uri, () => Task.FromResult <Stream>(null)); var request = new HttpRequestMessage(method, uri); // Act HttpResponseMessage actual = await options.GetResponseAsync(request); // Assert actual.ShouldNotBeNull(); actual.RequestMessage.ShouldBe(request); actual.Content.ShouldNotBeNull(); actual.Content.Headers?.ContentLength.ShouldBe(0); actual.Content.Headers?.ContentType?.MediaType.ShouldBe("application/json"); }
internal static async Task <string> SendAsync( HttpClientInterceptorOptions target, HttpMethod httpMethod, string requestUri, HttpContent content = null, HttpStatusCode statusCode = HttpStatusCode.OK, string mediaType = null, IDictionary <string, string> headers = null) { using (var httpClient = target.CreateHttpClient(ErroringHandler.Handler)) { using (var request = new HttpRequestMessage(httpMethod, requestUri)) { if (content != null) { request.Content = content; } if (headers != null) { foreach (var pair in headers) { request.Headers.Add(pair.Key, pair.Value); } } using (var response = await httpClient.SendAsync(request)) { response.StatusCode.ShouldBe(statusCode); if (mediaType != null) { response.Content.Headers.ContentType.MediaType.ShouldBe(mediaType); } return(await response.Content.ReadAsStringAsync()); } } } }
public static async Task GetResponseAsync_Returns_Empty_Response_If_Custom_Response_Header_Is_Null() { // Arrange var method = HttpMethod.Get; var uri = new Uri("https://google.com/"); IDictionary <string, string> responseHeaders = null; var options = new HttpClientInterceptorOptions() .RegisterByteArray(method, uri, contentFactory: Array.Empty <byte>, responseHeaders: responseHeaders); var request = new HttpRequestMessage(method, uri); // Act HttpResponseMessage actual = await options.GetResponseAsync(request); // Assert actual.ShouldNotBeNull(); actual.RequestMessage.ShouldBe(request); actual.Content.ShouldNotBeNull(); actual.Content.Headers.ContentLength.ShouldBe(0); }
public static async Task Register_For_Callback_Clears_Delegate_For_Predicate_If_Set_To_Null() { // Arrange var requestUri = new Uri("https://api.just-eat.com/"); var content = new { foo = "bar" }; bool wasDelegateInvoked = false; var builder = new HttpRequestInterceptionBuilder() .ForPost() .ForUri(requestUri) .WithInterceptionCallback((request) => wasDelegateInvoked = true) .WithInterceptionCallback(null as Predicate <HttpRequestMessage>); var options = new HttpClientInterceptorOptions().Register(builder); // Act await HttpAssert.PostAsync(options, requestUri.ToString(), content); // Assert wasDelegateInvoked.ShouldBeFalse(); }
public static async Task Builder_For_Any_Host_Path_And_Query_Registers_Interception() { // Arrange string expected = "<html>foo></html>"; var builder = new HttpRequestInterceptionBuilder() .ForAnyHost() .IgnoringPath() .IgnoringQuery() .WithContent(expected); var options = new HttpClientInterceptorOptions().Register(builder); // Act string actual1 = await HttpAssert.GetAsync(options, "http://google.com/blah/?foo=bar"); string actual2 = await HttpAssert.GetAsync(options, "http://bing.com/qux/?foo=baz"); // Assert actual1.ShouldBe(expected); actual2.ShouldBe(actual1); }
/// <summary> /// Registers an HTTP request interception, replacing any existing registration. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="method">The HTTP method to register an interception for.</param> /// <param name="uri">The request URI to register an interception for.</param> /// <param name="contentFactory">A delegate to a method that returns the raw response content.</param> /// <param name="statusCode">The optional HTTP status code to return.</param> /// <param name="mediaType">The optional media type for the content-type.</param> /// <param name="responseHeaders">The optional HTTP response headers.</param> /// <returns> /// The current <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/>, <paramref name="method"/>, <paramref name="uri"/> or /// <paramref name="contentFactory"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions Register( this HttpClientInterceptorOptions options, HttpMethod method, Uri uri, Func <byte[]> contentFactory, HttpStatusCode statusCode = HttpStatusCode.OK, string mediaType = HttpClientInterceptorOptions.JsonMediaType, IEnumerable <KeyValuePair <string, string> > responseHeaders = null) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (contentFactory == null) { throw new ArgumentNullException(nameof(contentFactory)); } IDictionary <string, IEnumerable <string> > multivalueHeaders = null; if (responseHeaders != null) { multivalueHeaders = new Dictionary <string, IEnumerable <string> >(); foreach (var pair in responseHeaders) { multivalueHeaders[pair.Key] = new[] { pair.Value }; } } return(options.Register( method, uri, () => Task.FromResult(contentFactory()), statusCode, mediaType, multivalueHeaders)); }
public static async Task Use_The_Same_Builder_For_Multiple_Registrations_On_The_Same_Host() { // Arrange var options = new HttpClientInterceptorOptions(); // Configure a response for https://api.github.com/orgs/justeat var builder = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/justeat") .WithJsonContent(new { id = 1516790, login = "******", url = "https://api.github.com/orgs/justeat" }); options.Register(builder); // Update the same builder to configure a response for https://api.github.com/orgs/dotnet builder.ForPath("orgs/dotnet") .WithJsonContent(new { id = 9141961, login = "******", url = "https://api.github.com/orgs/dotnet" }); options.Register(builder); var service = RestService.For <IGitHub>(options.CreateHttpClient("https://api.github.com")); // Act Organization justEatOrg = await service.GetOrganizationAsync("justeat"); Organization dotnetOrg = await service.GetOrganizationAsync("dotnet"); // Assert justEatOrg.ShouldNotBeNull(); justEatOrg.Id.ShouldBe("1516790"); justEatOrg.Login.ShouldBe("justeat"); justEatOrg.Url.ShouldBe("https://api.github.com/orgs/justeat"); // Assert dotnetOrg.ShouldNotBeNull(); dotnetOrg.Id.ShouldBe("9141961"); dotnetOrg.Login.ShouldBe("dotnet"); dotnetOrg.Url.ShouldBe("https://api.github.com/orgs/dotnet"); }
public static async Task WithFormContent_Returns_Correct_Response() { // Arrange var requestUri = "https://api.twitter.com/oauth/request_token"; var parameters = new Dictionary <string, string>() { { "oauth_callback_confirmed", "true" }, { "oauth_token", "a b c" }, { "oauth_token_secret", "U5LJUL3eS+fl9bj9xqHKXyHpBc8=" }, }; var options = new HttpClientInterceptorOptions(); var builder = new HttpRequestInterceptionBuilder() .Requests().ForPost().ForUrl(requestUri) .Responds().WithFormContent(parameters) .RegisterWith(options); // Act string actual = await HttpAssert.PostAsync(options, requestUri, new { }, mediaType : "application/x-www-form-urlencoded"); // Assert actual.ShouldBe("oauth_callback_confirmed=true&oauth_token=a+b+c&oauth_token_secret=U5LJUL3eS%2Bfl9bj9xqHKXyHpBc8%3D"); }
public static async Task Builder_Uses_Specified_Json_Serializer() { // Arrange var requestUri = "https://google.com/"; var expected = new { mode = EventResetMode.ManualReset }; var settings = new JsonSerializerSettings(); settings.Converters.Add(new StringEnumConverter()); var builder = new HttpRequestInterceptionBuilder() .ForPost() .ForUrl(requestUri) .WithJsonContent(expected, settings); var options = new HttpClientInterceptorOptions().Register(builder); // Act string actual = await HttpAssert.PostAsync(options, requestUri, new { }); // Assert actual.ShouldBe(@"{""mode"":""ManualReset""}"); }
public static async Task Intercept_Http_Get_To_Stream_Content_From_Disk() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForHost("xunit.github.io") .ForPath("settings.json") .WithContentStream(() => File.OpenRead("xunit.runner.json")); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); // Act string json = await client.GetStringAsync("http://xunit.github.io/settings.json"); // Assert json.ShouldNotBeNullOrWhiteSpace(); var config = JObject.Parse(json); config.Value <string>("methodDisplay").ShouldBe("method"); }
public static async Task Intercept_Custom_Http_Method() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForMethod(new HttpMethod("custom")) .ForHost("custom.domain.com") .ForQuery("length=2") .WithContent(() => new byte[] { 0, 1 }); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); using var message = new HttpRequestMessage(new HttpMethod("custom"), "http://custom.domain.com?length=2"); // Act using var response = await client.SendAsync(message); byte[] content = await response.Content.ReadAsByteArrayAsync(); // Assert content.ShouldBe(new byte[] { 0, 1 }); }
public static async Task Use_Multiple_Registrations() { // Arrange var justEat = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/justeat") .WithJsonContent(new { id = 1516790, login = "******", url = "https://api.github.com/orgs/justeat" }); var dotnet = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/dotnet") .WithJsonContent(new { id = 9141961, login = "******", url = "https://api.github.com/orgs/dotnet" }); var options = new HttpClientInterceptorOptions() .Register(justEat, dotnet); var service = RestService.For <IGitHub>(options.CreateHttpClient("https://api.github.com")); // Act Organization justEatOrg = await service.GetOrganizationAsync("justeat"); Organization dotnetOrg = await service.GetOrganizationAsync("dotnet"); // Assert justEatOrg.ShouldNotBeNull(); justEatOrg.Id.ShouldBe("1516790"); justEatOrg.Login.ShouldBe("justeat"); justEatOrg.Url.ShouldBe("https://api.github.com/orgs/justeat"); // Assert dotnetOrg.ShouldNotBeNull(); dotnetOrg.Id.ShouldBe("9141961"); dotnetOrg.Login.ShouldBe("dotnet"); dotnetOrg.Url.ShouldBe("https://api.github.com/orgs/dotnet"); }
public static async Task Inject_Latency_For_Http_Get_With_Cancellation() { // Arrange var latency = TimeSpan.FromMilliseconds(50); var builder = new HttpRequestInterceptionBuilder() .ForHost("www.google.co.uk") .WithInterceptionCallback(async(_, token) => { try { await Task.Delay(latency, token); } catch (TaskCanceledException) { // Ignored } finally { // Assert token.IsCancellationRequested.ShouldBeTrue(); } }); var options = new HttpClientInterceptorOptions() .Register(builder); using var cts = new CancellationTokenSource(TimeSpan.Zero); using var client = options.CreateHttpClient(); // Act await client.GetAsync("http://www.google.co.uk", cts.Token); // Assert cts.IsCancellationRequested.ShouldBeTrue(); }
public static async Task Intercept_Http_Put_For_Json_String() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForPut() .ForHttps() .ForHost("public.je-apis.com") .ForPath("baskets/123/user") .WithStatus(HttpStatusCode.Created) .WithContent(@"{ ""id"": 123 }"); var options = new HttpClientInterceptorOptions() .Register(builder); HttpStatusCode status; string json; using (var client = options.CreateHttpClient()) { using (var body = new StringContent(@"{ ""User"": { ""DisplayName"": ""John"" } }")) { // Act using (var response = await client.PutAsync("https://public.je-apis.com/baskets/123/user", body)) { status = response.StatusCode; json = await response.Content.ReadAsStringAsync(); } } } // Assert status.ShouldBe(HttpStatusCode.Created); var content = JObject.Parse(json); content.Value <int>("id").ShouldBe(123); }
public static async Task Register_For_Callback_Invokes_Delegate_With_Message_Asynchronous() { // Arrange var requestUri = new Uri("https://api.just-eat.com/"); var content = new { foo = "bar" }; bool wasDelegateInvoked = false; Func <HttpRequestMessage, Task> onIntercepted = async(request) => { request.ShouldNotBeNull(); request.Method.ShouldBe(HttpMethod.Post); request.RequestUri.ShouldBe(requestUri); string json = await request.Content.ReadAsStringAsync(); var body = JObject.Parse(json); body.Value <string>("foo").ShouldBe("bar"); wasDelegateInvoked = true; }; var builder = new HttpRequestInterceptionBuilder() .ForPost() .ForUri(requestUri) .WithInterceptionCallback(onIntercepted); var options = new HttpClientInterceptorOptions().Register(builder); // Act await HttpAssert.PostAsync(options, requestUri.ToString(), content); // Assert wasDelegateInvoked.ShouldBeTrue(); }
public static async Task GetResponseAsync_Returns_Empty_Response_If_Individual_Custom_Response_Headers() { // Arrange string url = "https://google.com/"; var builder = new HttpRequestInterceptionBuilder() .ForUrl(url) .WithResponseHeader("a", "b") .WithResponseHeader("c", "d", "e", "f") .WithResponseHeader("c", "d", "e"); var options = new HttpClientInterceptorOptions() .Register(builder); var request = new HttpRequestMessage(HttpMethod.Get, url); // Act HttpResponseMessage actual = await options.GetResponseAsync(request); // Assert actual.ShouldNotBeNull(); actual.Headers.GetValues("a").ShouldBe(new[] { "b" }); actual.Headers.GetValues("c").ShouldBe(new[] { "d", "e" }); }
/// <summary> /// Registers an HTTP GET request for the specified JSON content. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="uriString">The request URL.</param> /// <param name="content">The object to serialize as JSON as the content.</param> /// <param name="statusCode">The optional HTTP status code to return.</param> /// <returns> /// The value specified by <paramref name="options"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="content"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions RegisterGet( this HttpClientInterceptorOptions options, string uriString, object content, HttpStatusCode statusCode = HttpStatusCode.OK) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (content == null) { throw new ArgumentNullException(nameof(content)); } Func <byte[]> contentFactory = () => { string json = JsonConvert.SerializeObject(content); return(Encoding.UTF8.GetBytes(json)); }; return(options.Register(HttpMethod.Get, new Uri(uriString), contentFactory, statusCode)); }
/// <summary> /// Creates an <see cref="HttpClient"/> that uses the interceptors registered for the specified options and base address. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="baseAddress">The base address to use for the created HTTP client.</param> /// <param name="innerHandler">The optional inner <see cref="HttpMessageHandler"/>.</param> /// <returns> /// The <see cref="HttpClient"/> that uses the specified <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> is <see langword="null"/>. /// </exception> public static HttpClient CreateHttpClient(this HttpClientInterceptorOptions options, string baseAddress, HttpMessageHandler innerHandler = null) { Uri baseAddressUri = new Uri(baseAddress, UriKind.RelativeOrAbsolute); return(options.CreateHttpClient(baseAddressUri, innerHandler)); }
/// <summary> /// Registers a bundle of HTTP request interceptions from a specified JSON file. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to register the bundle with.</param> /// <param name="path">The path of the JSON file containing the serialized bundle.</param> /// <returns> /// The value specified by <paramref name="options"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="path"/> is <see langword="null"/>. /// </exception> /// <exception cref="NotSupportedException"> /// The version of the serialized bundle is not supported. /// </exception> public static HttpClientInterceptorOptions RegisterBundle(this HttpClientInterceptorOptions options, string path) { return(options.RegisterBundle(path, Array.Empty <KeyValuePair <string, string> >())); }
/// <summary> /// Registers one or more HTTP request interceptions, replacing any existing registrations. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="collection">An array of one or more <see cref="HttpRequestInterceptionBuilder"/> instances to use to create the registration(s).</param> /// <returns> /// The current <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="collection"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions Register( this HttpClientInterceptorOptions options, params HttpRequestInterceptionBuilder[] collection) { return(options.Register(collection as IEnumerable <HttpRequestInterceptionBuilder>)); }
/// <summary> /// Initializes a new instance of the <see cref="InterceptingHttpMessageHandler"/> class. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to use.</param> /// <param name="innerHandler">The inner <see cref="HttpMessageHandler"/>.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> is <see langword="null"/>. /// </exception> public InterceptingHttpMessageHandler(HttpClientInterceptorOptions options, HttpMessageHandler innerHandler) : base(innerHandler) { _options = options ?? throw new ArgumentNullException(nameof(options)); }