Skip to content

Commit

Permalink
Merge pull request #21 from myarichuk/develop
Browse files Browse the repository at this point in the history
minor convenience methods in client builder, some more testing
  • Loading branch information
myarichuk authored May 3, 2020
2 parents 5b34d8f + 68d706e commit 3e26355
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 119 deletions.
20 changes: 20 additions & 0 deletions Simple.HttpClientFactory.Tests/BasicClientBuilderTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
Expand All @@ -24,6 +26,24 @@ public BasicClientBuilderTests()
.WithBody("Hello world!"));
}

[Fact]
public async Task Will_send_default_headers()
{
var trafficRecorder = new TrafficRecorderMessageHandler(new List<string>());

var client = HttpClientFactory
.Create(trafficRecorder)
.WithDefaultHeaders(new Dictionary<string, string> { { "foobar", "xyz123" } })
.Build();

_ = await client.GetAsync(_server.Urls[0] + "/hello/world");

Assert.Single(trafficRecorder.Traffic); //sanity check
Assert.True(trafficRecorder.Traffic[0].Item1.Headers.Contains("foobar"));
Assert.Equal("xyz123", trafficRecorder.Traffic[0].Item1.Headers.GetValues("foobar").FirstOrDefault());
}


[Fact]
public async Task Can_do_http_get_with_plain_client()
{
Expand Down
72 changes: 72 additions & 0 deletions Simple.HttpClientFactory.Tests/EventMessageHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
namespace Simple.HttpClientFactory.Tests
{
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// Defines the <see cref="EventMessageHandler" />.
/// </summary>
public class EventMessageHandler : DelegatingHandler
{
/// <summary>
/// Defines the Request.
/// </summary>
public event EventHandler<RequestEventArgs> Request;

/// <summary>
/// Defines the Response.
/// </summary>
public event EventHandler<ResponseEventArgs> Response;

/// <summary>
/// Defines the _visitedMiddleware.
/// </summary>
private readonly List<string> _visitedMiddleware;

/// <summary>
/// Initializes a new instance of the <see cref="EventMessageHandler"/> class.
/// </summary>
/// <param name="visitedMiddleware">The visitedMiddleware<see cref="List{string}"/>.</param>
public EventMessageHandler(List<string> visitedMiddleware) => _visitedMiddleware = visitedMiddleware;

/// <summary>
/// Defines the <see cref="RequestEventArgs" />.
/// </summary>
public class RequestEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the Request.
/// </summary>
public HttpRequestMessage Request { get; set; }
}

/// <summary>
/// Defines the <see cref="ResponseEventArgs" />.
/// </summary>
public class ResponseEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the Response.
/// </summary>
public HttpResponseMessage Response { get; set; }
}

/// <summary>
/// The SendAsync.
/// </summary>
/// <param name="request">The request<see cref="HttpRequestMessage"/>.</param>
/// <param name="cancellationToken">The cancellationToken<see cref="CancellationToken"/>.</param>
/// <returns>The <see cref="Task{HttpResponseMessage}"/>.</returns>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Request?.Invoke(this, new RequestEventArgs { Request = request });
var response = await base.SendAsync(request, cancellationToken);
Response?.Invoke(this, new ResponseEventArgs { Response = response });
_visitedMiddleware.Add(nameof(EventMessageHandler));
return response;
}
}
}
52 changes: 1 addition & 51 deletions Simple.HttpClientFactory.Tests/MiddlewareAndPolicyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
Expand All @@ -14,7 +13,7 @@

namespace Simple.HttpClientFactory.Tests
{
public class MiddlewareAndPolicyTests
public partial class MiddlewareAndPolicyTests
{
private readonly WireMockServer _server;
private readonly List<string> _visitedMiddleware = new List<string>();
Expand Down Expand Up @@ -182,54 +181,5 @@ public async Task Retry_policy_should_work_with_single_middleware()
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("Hello world!", await response.Content.ReadAsStringAsync());
}


public class EventMessageHandler : DelegatingHandler
{
public event EventHandler<RequestEventArgs> Request;
public event EventHandler<ResponseEventArgs> Response;

private readonly List<string> _visitedMiddleware;

public EventMessageHandler(List<string> visitedMiddleware) => _visitedMiddleware = visitedMiddleware;

public class RequestEventArgs : EventArgs
{
public HttpRequestMessage Request { get; set; }
}

public class ResponseEventArgs : EventArgs
{
public HttpResponseMessage Response { get; set; }
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Request?.Invoke(this ,new RequestEventArgs { Request = request });
var response = await base.SendAsync(request, cancellationToken);
Response?.Invoke(this, new ResponseEventArgs { Response = response });
_visitedMiddleware.Add(nameof(EventMessageHandler));
return response;
}
}

public class TrafficRecorderMessageHandler : DelegatingHandler
{
public List<(HttpRequestMessage, HttpResponseMessage)> Traffic { get; } = new List<(HttpRequestMessage, HttpResponseMessage)>();

private readonly List<string> _visitedMiddleware;

public TrafficRecorderMessageHandler(List<string> visitedMiddleware) => _visitedMiddleware = visitedMiddleware;

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("foobar", "foobar");
var response = await base.SendAsync(request, cancellationToken);
_visitedMiddleware.Add(nameof(TrafficRecorderMessageHandler));
Traffic.Add((request, response));

return response;
}
}
}
}
54 changes: 2 additions & 52 deletions Simple.HttpClientFactory.Tests/MiddlewareDelegateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
Expand All @@ -12,7 +10,7 @@

namespace Simple.HttpClientFactory.Tests
{
public class MiddlewareDelegateTests
public partial class MiddlewareDelegateTests
{
private readonly WireMockServer _server;
private readonly List<string> _visitedMiddleware = new List<string>();
Expand Down Expand Up @@ -89,54 +87,6 @@ public async Task Multiple_middleware_handlers_with_reverse_order_should_work()
Assert.Equal(HttpStatusCode.OK, trafficRecorderMessageHandler.Traffic[0].Item2.StatusCode);

Assert.Equal(new [] { nameof(EventMessageHandler), nameof(TrafficRecorderMessageHandler) }, _visitedMiddleware);
}

public class EventMessageHandler : DelegatingHandler
{
public event EventHandler<RequestEventArgs> Request;
public event EventHandler<ResponseEventArgs> Response;

private readonly List<string> _visitedMiddleware;

public EventMessageHandler(List<string> visitedMiddleware) => _visitedMiddleware = visitedMiddleware;

public class RequestEventArgs : EventArgs
{
public HttpRequestMessage Request { get; set; }
}

public class ResponseEventArgs : EventArgs
{
public HttpResponseMessage Response { get; set; }
}

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Request?.Invoke(this ,new RequestEventArgs { Request = request });
var response = await base.SendAsync(request, cancellationToken);
Response?.Invoke(this, new ResponseEventArgs { Response = response });
_visitedMiddleware.Add(nameof(EventMessageHandler));
return response;
}
}

public class TrafficRecorderMessageHandler : DelegatingHandler
{
public List<(HttpRequestMessage, HttpResponseMessage)> Traffic { get; } = new List<(HttpRequestMessage, HttpResponseMessage)>();

private readonly List<string> _visitedMiddleware;

public TrafficRecorderMessageHandler(List<string> visitedMiddleware) => _visitedMiddleware = visitedMiddleware;

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("foobar", "foobar");
var response = await base.SendAsync(request, cancellationToken);
_visitedMiddleware.Add(nameof(TrafficRecorderMessageHandler));
Traffic.Add((request, response));

return response;
}
}
}
}
}
32 changes: 32 additions & 0 deletions Simple.HttpClientFactory.Tests/PollyHttpMessageHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Polly;
using Simple.HttpClientFactory.Polly;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace Simple.HttpClientFactory.Tests
{
//some sanity checks
public class PollyHttpMessageHandlerTests
{
[Fact]
public void Ctor_with_null_should_throw() =>
Assert.Throws<ArgumentNullException>(() => new PolicyHttpMessageHandler(null));

[Fact]
public async Task Null_param_in_send_async_should_throw()
{
var middlewareHandler = new PolicyHttpMessageHandler(Policy<HttpResponseMessage>
.Handle<HttpRequestException>()
.OrResult(result => (int)result.StatusCode >= 500 || result.StatusCode == HttpStatusCode.RequestTimeout)
.WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(1)));

using(var client = HttpClientFactory.Create(middlewareHandler).Build())
await Assert.ThrowsAsync<ArgumentNullException>(() => client.SendAsync(null));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,9 @@
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="2.8.1">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Flurl" Version="2.8.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="WireMock.Net" Version="1.2.6" />
<PackageReference Include="WireMock.Net" Version="1.2.7" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>
Expand Down
45 changes: 45 additions & 0 deletions Simple.HttpClientFactory.Tests/TrafficRecorderMessageHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
namespace Simple.HttpClientFactory.Tests
{
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

/// <summary>
/// Defines the <see cref="TrafficRecorderMessageHandler" />.
/// </summary>
public class TrafficRecorderMessageHandler : DelegatingHandler
{
/// <summary>
/// Gets the Traffic.
/// </summary>
public List<(HttpRequestMessage, HttpResponseMessage)> Traffic { get; } = new List<(HttpRequestMessage, HttpResponseMessage)>();

/// <summary>
/// Defines the _visitedMiddleware.
/// </summary>
private readonly List<string> _visitedMiddleware;

/// <summary>
/// Initializes a new instance of the <see cref="TrafficRecorderMessageHandler"/> class.
/// </summary>
/// <param name="visitedMiddleware">The visitedMiddleware<see cref="List{string}"/>.</param>
public TrafficRecorderMessageHandler(List<string> visitedMiddleware) => _visitedMiddleware = visitedMiddleware;

/// <summary>
/// The SendAsync.
/// </summary>
/// <param name="request">The request<see cref="HttpRequestMessage"/>.</param>
/// <param name="cancellationToken">The cancellationToken<see cref="CancellationToken"/>.</param>
/// <returns>The <see cref="Task{HttpResponseMessage}"/>.</returns>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("foobar", "foobar");
var response = await base.SendAsync(request, cancellationToken);
_visitedMiddleware.Add(nameof(TrafficRecorderMessageHandler));
Traffic.Add((request, response));

return response;
}
}
}
16 changes: 12 additions & 4 deletions Simple.HttpClientFactory/HttpClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
#if NETCOREAPP2_1
using System.Net.Security;
#endif
Expand All @@ -19,13 +20,20 @@ internal class HttpClientBuilder : IHttpClientBuilder
private readonly List<DelegatingHandler> _middlewareHandlers = new List<DelegatingHandler>();
private readonly Dictionary<string, string> _defaultHeaders = new Dictionary<string, string>();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IHttpClientBuilder WithDefaultHeader(string name, string value)
{
if(!_defaultHeaders.ContainsKey(name))
_defaultHeaders.Add(name, value);

return this;
}

public IHttpClientBuilder WithDefaultHeaders(IReadOnlyDictionary<string, string> headers)
{
foreach(var kvp in headers)
{
if(!_defaultHeaders.ContainsKey(kvp.Key))
_defaultHeaders.Add(kvp.Key, kvp.Value);
}
WithDefaultHeader(kvp.Key, kvp.Value);

return this;
}

Expand Down
7 changes: 6 additions & 1 deletion Simple.HttpClientFactory/IHttpClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ namespace Simple.HttpClientFactory
public interface IHttpClientBuilder
{
/// <summary>
/// Add default headers to be added to teach request
/// Add default headers to be added to each request
/// </summary>
IHttpClientBuilder WithDefaultHeader(string name, string value);

/// <summary>
/// Add default headers to be added to each request
/// </summary>
IHttpClientBuilder WithDefaultHeaders(IReadOnlyDictionary<string, string> headers);

Expand Down
Loading

0 comments on commit 3e26355

Please sign in to comment.