Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add redirect,retry and compression handlers to HttpClient library for dotnet #589

Merged
merged 7 commits into from
Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Http.HttpClient.Extensions;
using Microsoft.Kiota.Http.HttpClient.Middleware.Options;
using Xunit;
using HttpMethod = Microsoft.Kiota.Abstractions.HttpMethod;

namespace Microsoft.Kiota.Http.HttpClient.Tests.Extensions
{
public class HttpRequestMessageExtensionsTests
{
[Fact]
public void GetMiddlewareOptionCanExtractMiddleWareOptionFromHttpRequestMessage()
{
// Arrange
var requestInfo = new RequestInformation()
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
};
var redirectHandlerOption = new RedirectHandlerOption()
{
MaxRedirect = 7
};
requestInfo.AddMiddlewareOptions(redirectHandlerOption);
// Act and get a request message
var requestMessage = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
var extractedOption = requestMessage.GetMiddlewareOption<RedirectHandlerOption>();
// Assert
Assert.NotNull(extractedOption);
Assert.Equal(redirectHandlerOption, extractedOption);
Assert.Equal(7, redirectHandlerOption.MaxRedirect);
}

[Fact]
public async Task CloneAsyncWithEmptyHttpContent()
{
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
};
var originalRequest = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
HttpRequestMessage clonedRequest = await originalRequest.CloneAsync();

Assert.NotNull(clonedRequest);
Assert.Equal(originalRequest.Method, clonedRequest.Method);
Assert.Equal(originalRequest.RequestUri, clonedRequest.RequestUri);
Assert.Null(clonedRequest.Content);
}

[Fact]
public async Task CloneAsyncWithHttpContent()
{
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
};
requestInfo.SetStreamContent(new MemoryStream(Encoding.UTF8.GetBytes("contents")));
var originalRequest = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
originalRequest.Content = new StringContent("contents");

var clonedRequest = await originalRequest.CloneAsync();
var clonedRequestContents = await clonedRequest.Content?.ReadAsStringAsync();

Assert.NotNull(clonedRequest);
Assert.Equal(originalRequest.Method, clonedRequest.Method);
Assert.Equal(originalRequest.RequestUri, clonedRequest.RequestUri);
Assert.Equal("contents", clonedRequestContents);
Assert.Equal(originalRequest.Content?.Headers.ContentType, clonedRequest.Content?.Headers.ContentType);
}

[Fact]
public async Task CloneAsyncWithMiddlewareOption()
{
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
};
var redirectHandlerOption = new RedirectHandlerOption()
{
MaxRedirect = 7
};
requestInfo.AddMiddlewareOptions(redirectHandlerOption);
var originalRequest = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
originalRequest.Content = new StringContent("contents");

var clonedRequest = await originalRequest.CloneAsync();

Assert.NotNull(clonedRequest);
Assert.Equal(originalRequest.Method, clonedRequest.Method);
Assert.Equal(originalRequest.RequestUri, clonedRequest.RequestUri);
Assert.NotEmpty(clonedRequest.Options);
Assert.Equal(redirectHandlerOption, clonedRequest.Options.First().Value);
Assert.Equal(originalRequest.Content?.Headers.ContentType, clonedRequest.Content?.Headers.ContentType);
}

[Fact]
public void IsBufferedReturnsTrueForGetRequest()
{
// Arrange
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.GET,
URI = new Uri("http://localhost")
};
var originalRequest = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
// Act
var response = originalRequest.IsBuffered();
// Assert
Assert.True(response, "Unexpected content type");
}
[Fact]
public void IsBufferedReturnsTrueForPostWithNoContent()
{
// Arrange
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.POST,
URI = new Uri("http://localhost")
};
var originalRequest = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
// Act
var response = originalRequest.IsBuffered();
// Assert
Assert.True(response, "Unexpected content type");
}
[Fact]
public void IsBufferedReturnsTrueForPostWithBufferStringContent()
{
// Arrange
byte[] data = new byte[] { 1, 2, 3, 4, 5 };
var requestInfo = new RequestInformation
{
HttpMethod = HttpMethod.POST,
URI = new Uri("http://localhost"),
Content = new MemoryStream(data)
};
var originalRequest = HttpCore.GetRequestMessageFromRequestInformation(requestInfo);
// Act
var response = originalRequest.IsBuffered();
// Assert
Assert.True(response, "Unexpected content type");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Kiota.Http.HttpClient.Middleware;
using Microsoft.Kiota.Http.HttpClient.Tests.Mocks;
using Xunit;

namespace Microsoft.Kiota.Http.HttpClient.Tests.Middleware
{
public class CompressionHandlerTests: IDisposable
{
private readonly MockRedirectHandler _testHttpMessageHandler;
private readonly CompressionHandler _compressionHandler;
private readonly HttpMessageInvoker _invoker;

public CompressionHandlerTests()
{
this._testHttpMessageHandler = new MockRedirectHandler();
this._compressionHandler = new CompressionHandler
{
InnerHandler = this._testHttpMessageHandler
};
this._invoker = new HttpMessageInvoker(this._compressionHandler);
}

public void Dispose()
{
this._invoker.Dispose();
GC.SuppressFinalize(this);
}

[Fact]
public void CompressionHandlerShouldConstructHandler()
{
Assert.NotNull(this._compressionHandler.InnerHandler);
}

[Fact]
public async Task CompressionHandlerShouldAddAcceptEncodingGzipHeaderWhenNonIsPresent()
{
// Arrange
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.org/foo");
HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.OK);
this._testHttpMessageHandler.SetHttpResponse(httpResponse);// set the mock response
// Act
HttpResponseMessage response = await this._invoker.SendAsync(httpRequestMessage, new CancellationToken());
// Assert
Assert.Same(httpRequestMessage, response.RequestMessage);
Assert.NotNull(response.RequestMessage);
Assert.Contains(new StringWithQualityHeaderValue(CompressionHandler.GZip), response.RequestMessage.Headers.AcceptEncoding);
}

[Fact]
public async Task CompressionHandlerShouldDecompressResponseWithContentEncodingGzipHeader()
{
// Arrange
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.org/foo");
httpRequestMessage.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue(CompressionHandler.GZip));
string stringToCompress = "sample string content";
// Compress response
HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new MockCompressedContent(new StringContent(stringToCompress))
};
httpResponse.Content.Headers.ContentEncoding.Add(CompressionHandler.GZip);
this._testHttpMessageHandler.SetHttpResponse(httpResponse);// set the mock response
// Act
HttpResponseMessage decompressedResponse = await this._invoker.SendAsync(httpRequestMessage, new CancellationToken());
string responseContentString = await decompressedResponse.Content.ReadAsStringAsync();
// Assert
Assert.Same(httpResponse, decompressedResponse);
Assert.Same(httpRequestMessage, decompressedResponse.RequestMessage);
Assert.Equal(stringToCompress, responseContentString);
}

[Fact]
public async Task CompressionHandlerShouldNotDecompressResponseWithoutContentEncodingGzipHeader()
{
// Arrange
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.org/foo");
string stringToCompress = "Microsoft Graph";
HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new MockCompressedContent(new StringContent(stringToCompress))
};
this._testHttpMessageHandler.SetHttpResponse(httpResponse);// set the mock response
// Act
HttpResponseMessage compressedResponse = await this._invoker.SendAsync(httpRequestMessage, new CancellationToken());
string responseContentString = await compressedResponse.Content.ReadAsStringAsync();
// Assert
Assert.Same(httpResponse, compressedResponse);
Assert.Same(httpRequestMessage, compressedResponse.RequestMessage);
Assert.NotEqual(stringToCompress, responseContentString);
}

[Fact]
public async Task CompressionHandlerShouldKeepContentHeadersAfterDecompression()
{
// Arrange
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://example.org/foo");
// setup the http response
string stringToCompress = "Microsoft Graph";
StringContent stringContent = new StringContent(stringToCompress); // setup the content object
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
stringContent.Headers.ContentEncoding.Add(CompressionHandler.GZip);
HttpResponseMessage httpResponse = new HttpResponseMessage(HttpStatusCode.OK)// setup the HttpResponseMessage object
{
Content = new MockCompressedContent(stringContent)
};
httpResponse.Headers.CacheControl = new CacheControlHeaderValue { Private = true };
// Examples of Custom Headers returned by Microsoft Graph
httpResponse.Headers.Add("request-id", Guid.NewGuid().ToString());
httpResponse.Headers.Add("OData-Version", "4.0");

this._testHttpMessageHandler.SetHttpResponse(httpResponse);// set the mock response
// Arrange
HttpResponseMessage compressedResponse = await this._invoker.SendAsync(httpRequestMessage, new CancellationToken());
string decompressedResponseString = await compressedResponse.Content.ReadAsStringAsync();
// Assert
Assert.Equal(decompressedResponseString, stringToCompress);
// Ensure that headers in the compressedResponse are the same as in the original, expected response.
Assert.NotEmpty(compressedResponse.Headers);
Assert.NotEmpty(compressedResponse.Content.Headers);
Assert.Equal(httpResponse.Headers, compressedResponse.Headers, new HttpHeaderComparer());
Assert.Equal(httpResponse.Content.Headers, compressedResponse.Content.Headers, new HttpHeaderComparer());
}

private class HttpHeaderComparer : IEqualityComparer<KeyValuePair<string, IEnumerable<string>>>
{
public bool Equals(KeyValuePair<string, IEnumerable<string>> x, KeyValuePair<string, IEnumerable<string>> y)
{
// For each key, the collection of header values should be equal.
return x.Key == y.Key && x.Value.SequenceEqual(y.Value);
}

public int GetHashCode(KeyValuePair<string, IEnumerable<string>> obj)
{
return obj.Key.GetHashCode();
}
}
}
}
Loading