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

Allow all headers to be set as Response headers #142

Merged
merged 6 commits into from
May 25, 2018
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
28 changes: 27 additions & 1 deletion examples/WireMock.Net.Console.Proxy.NETCoreApp2/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
using Newtonsoft.Json;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
using WireMock.Settings;

Expand All @@ -8,6 +14,9 @@ class Program
{
static void Main(string[] args)
{
RunTestDifferentPort().Wait(20000); // prints "1"
RunTestDifferentPort().Wait(20000); // prints "1"

var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://localhost:9091", "https://localhost:9443" },
Expand All @@ -32,5 +41,22 @@ static void Main(string[] args)
System.Console.ReadKey();
server.Stop();
}

private static async Task RunTestDifferentPort()
{
var server = FluentMockServer.Start();

server.Given(Request.Create().WithPath("/").UsingGet())
.RespondWith(Response.Create().WithStatusCode(200).WithBody("Hello"));

Thread.Sleep(1000);

var response = await new HttpClient().GetAsync(server.Urls[0]);
response.EnsureSuccessStatusCode();

System.Console.WriteLine("RunTestDifferentPort - server.LogEntries.Count() = " + server.LogEntries.Count());

server.Stop();
}
}
}
2 changes: 1 addition & 1 deletion src/WireMock.Net.StandAlone/WireMock.Net.StandAlone.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight StandAlone Http Mocking Server for .Net.</Description>
<AssemblyTitle>WireMock.Net.StandAlone</AssemblyTitle>
<Version>1.0.3.17</Version>
<Version>1.0.3.18</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
2 changes: 0 additions & 2 deletions src/WireMock.Net/Owin/AspNetCoreSelfHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ public Task StartAsync()
#endif
.Build();

IsStarted = true;

return Task.Run(() =>
{
StartServers();
Expand Down
86 changes: 36 additions & 50 deletions src/WireMock.Net/Owin/OwinResponseMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,48 +24,27 @@ public class OwinResponseMapper

// https://msdn.microsoft.com/en-us/library/78h415ay(v=vs.110).aspx
#if !NETSTANDARD
private static readonly IDictionary<string, Action<IOwinResponse, WireMockList<string>>> RestrictedResponseHeaders = new Dictionary<string, Action<IOwinResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
private static readonly IDictionary<string, Action<IOwinResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<IOwinResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
#else
private static readonly IDictionary<string, Action<HttpResponse, WireMockList<string>>> RestrictedResponseHeaders = new Dictionary<string, Action<HttpResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
private static readonly IDictionary<string, Action<HttpResponse, WireMockList<string>>> ResponseHeadersToFix = new Dictionary<string, Action<HttpResponse, WireMockList<string>>>(StringComparer.OrdinalIgnoreCase) {
#endif
{ HttpKnownHeaderNames.Accept, null },
{ HttpKnownHeaderNames.Connection, null },
{ HttpKnownHeaderNames.ContentLength, null },
{ HttpKnownHeaderNames.ContentType, (r, v) => r.ContentType = v.FirstOrDefault() },
{ HttpKnownHeaderNames.Date, null },
{ HttpKnownHeaderNames.Expect, null },
{ HttpKnownHeaderNames.Host, null },
{ HttpKnownHeaderNames.IfModifiedSince, null },
{ HttpKnownHeaderNames.KeepAlive, null },
{ HttpKnownHeaderNames.Range, null },
{ HttpKnownHeaderNames.Referer, null },
{ HttpKnownHeaderNames.TransferEncoding, null },
{ HttpKnownHeaderNames.UserAgent, null },
{ HttpKnownHeaderNames.ProxyConnection, null },
{ HttpKnownHeaderNames.WWWAuthenticate, null }
{ HttpKnownHeaderNames.ContentType, (r, v) => r.ContentType = v.FirstOrDefault() }
};

/// <summary>
/// MapAsync ResponseMessage to OwinResponse
/// </summary>
/// <param name="responseMessage"></param>
/// <param name="response"></param>
public async Task MapAsync(ResponseMessage responseMessage
private void SetResponseHeaders(ResponseMessage responseMessage
#if !NETSTANDARD
, IOwinResponse response
#else
, HttpResponse response
#endif
)
)
{
response.StatusCode = responseMessage.StatusCode;

// Set headers
foreach (var pair in responseMessage.Headers)
{
if (RestrictedResponseHeaders.ContainsKey(pair.Key))
if (ResponseHeadersToFix.ContainsKey(pair.Key))
{
RestrictedResponseHeaders[pair.Key]?.Invoke(response, pair.Value);
ResponseHeadersToFix[pair.Key]?.Invoke(response, pair.Value);
}
else
{
Expand All @@ -76,41 +55,48 @@ public async Task MapAsync(ResponseMessage responseMessage
#endif
}
}
}

if (responseMessage.Body == null && responseMessage.BodyAsBytes == null && responseMessage.BodyAsFile == null && responseMessage.BodyAsJson == null)
{
return;
}
/// <summary>
/// Map ResponseMessage to OwinResponse/HttpResponse
/// </summary>
/// <param name="responseMessage"></param>
/// <param name="response"></param>
public async Task MapAsync(ResponseMessage responseMessage
#if !NETSTANDARD
, IOwinResponse response
#else
, HttpResponse response
#endif
)
{
response.StatusCode = responseMessage.StatusCode;

byte[] bytes = null;
if (responseMessage.BodyAsBytes != null)
{
await response.Body.WriteAsync(responseMessage.BodyAsBytes, 0, responseMessage.BodyAsBytes.Length);
return;
bytes = responseMessage.BodyAsBytes;
}

if (responseMessage.BodyAsFile != null)
else if (responseMessage.BodyAsFile != null)
{
byte[] bytes = File.ReadAllBytes(responseMessage.BodyAsFile);

await response.Body.WriteAsync(bytes, 0, bytes.Length);
return;
bytes = File.ReadAllBytes(responseMessage.BodyAsFile);
}

if (responseMessage.BodyAsJson != null)
else if (responseMessage.BodyAsJson != null)
{
Formatting formatting = responseMessage.BodyAsJsonIndented == true ? Formatting.Indented : Formatting.None;
string jsonBody = JsonConvert.SerializeObject(responseMessage.BodyAsJson, new JsonSerializerSettings { Formatting = formatting, NullValueHandling = NullValueHandling.Ignore });
using (var writer = new StreamWriter(response.Body, responseMessage.BodyEncoding ?? _utf8NoBom))
{
await writer.WriteAsync(jsonBody);
}

return;
bytes = (responseMessage.BodyEncoding ?? _utf8NoBom).GetBytes(jsonBody);
}
else if (responseMessage.Body != null)
{
bytes = (responseMessage.BodyEncoding ?? _utf8NoBom).GetBytes(responseMessage.Body);
}

using (var writer = new StreamWriter(response.Body, responseMessage.BodyEncoding ?? _utf8NoBom))
SetResponseHeaders(responseMessage, response);

if (bytes != null)
{
await writer.WriteAsync(responseMessage.Body);
await response.Body.WriteAsync(bytes, 0, bytes.Length);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/WireMock.Net/Server/FluentMockServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,13 @@ private FluentMockServer(IFluentMockServerSettings settings)
{
throw new Exception($"Service start failed with error: {_httpServer.RunningException.Message}", _httpServer.RunningException);
}

// Respect start timeout setting by throwing TimeoutException
if (ctsStartTimeout.IsCancellationRequested)
{
throw new TimeoutException($"Service start timed out after {TimeSpan.FromMilliseconds(settings.StartTimeout)}");
}

ctsStartTimeout.Token.WaitHandle.WaitOne(ServerStartDelay);
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/WireMock.Net/WireMock.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Lightweight Http Mocking Server for .Net, inspired by WireMock from the Java landscape.</Description>
<AssemblyTitle>WireMock.Net</AssemblyTitle>
<Version>1.0.3.17</Version>
<Version>1.0.3.18</Version>
<Authors>Stef Heyenrath</Authors>
<TargetFrameworks>net452;net46;netstandard1.3;netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down Expand Up @@ -36,10 +36,6 @@
<Compile Remove="Util\NamedReaderWriterLocker.cs" />
</ItemGroup>

<ItemGroup>
<None Remove="Server\FluentMockServer.cs~RF44936b9f.TMP" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="11.1.0">
<PrivateAssets>All</PrivateAssets>
Expand Down
16 changes: 8 additions & 8 deletions test/WireMock.Net.Tests/FluentMockServerTests.Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Net.Http.Headers;
using System.Threading.Tasks;
using NFluent;
using WireMock.Matchers.Request;
using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;
Expand Down Expand Up @@ -190,29 +189,30 @@ public async Task FluentMockServer_Proxy_Should_preserve_content_header_in_proxi
[Fact]
public async Task FluentMockServer_Proxy_Should_change_absolute_location_header_in_proxied_response()
{
// given
_serverForProxyForwarding = FluentMockServer.Start();
// Assign
var settings = new FluentMockServerSettings { AllowPartialMapping = false };
_serverForProxyForwarding = FluentMockServer.Start(settings);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps names these 2 servers more specifically as it is quite hard to follow. _serverThatReturnsRedirects and serverThatProxies ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your comment, however for me it's clear for now. But I will think about this to see if I want to rename the these variables.

_serverForProxyForwarding
.Given(Request.Create().WithPath("/*"))
.RespondWith(Response.Create()
.WithStatusCode(HttpStatusCode.Redirect)
.WithHeader("Location", _serverForProxyForwarding.Urls[0] + "testpath"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This creates a server that could redirect indefinitely I think. Request.Create().WithPath("/") instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it has to be like this, else test fails.


_server = FluentMockServer.Start();
_server = FluentMockServer.Start(settings);
_server
.Given(Request.Create().WithPath("/*"))
.Given(Request.Create().WithPath("/prx"))
.RespondWith(Response.Create().WithProxy(_serverForProxyForwarding.Urls[0]));

// when
// Act
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_server.Urls[0])
RequestUri = new Uri(_server.Urls[0] + "/prx")
};
var httpClientHandler = new HttpClientHandler { AllowAutoRedirect = false };
var response = await new HttpClient(httpClientHandler).SendAsync(requestMessage);

// then
// Assert
Check.That(response.Headers.Contains("Location")).IsTrue();
Check.That(response.Headers.GetValues("Location")).ContainsExactly(_server.Urls[0] + "testpath");
}
Expand Down
54 changes: 20 additions & 34 deletions test/WireMock.Net.Tests/FluentMockServerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,11 @@ public async Task FluentMockServer_Should_respond_to_request_bodyAsBytes()
Check.That(responseAsBytes).ContainsExactly(new byte[] { 48, 49 });
}

public static IEnumerable<object[]> ValidMatchersForHelloServerJsonMessage =>
new List<object[]>
[Fact]
public async Task FluentMockServer_Should_respond_to_valid_matchers_when_sent_json()
{
// Assign
var validMatchersForHelloServerJsonMessage = new List<object[]>
{
new object[] { new WildcardMatcher("*Hello server*"), "application/json" },
new object[] { new WildcardMatcher("*Hello server*"), "text/plain" },
Expand All @@ -364,24 +367,25 @@ public async Task FluentMockServer_Should_respond_to_request_bodyAsBytes()
new object[] { new JsonPathMatcher("$..[?(@.message == 'Hello server')]"), "text/plain" }
};

[Theory]
Copy link
Collaborator

@alastairtree alastairtree May 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason for not using the parameterised tests? The test cleanup at the end could also be done by making the class IDisposable if preferred.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason the tests failed on my local machine, so I just fixed it this way.

[MemberData(nameof(ValidMatchersForHelloServerJsonMessage))]
public async Task FluentMockServer_Should_respond_to_valid_matchers_when_sent_json(IMatcher matcher, string contentType)
{
// Assign
_server = FluentMockServer.Start();

_server
.Given(Request.Create().WithPath("/foo").WithBody(matcher))
.RespondWith(Response.Create().WithBody("Hello client"));
foreach (var item in validMatchersForHelloServerJsonMessage)
{
_server
.Given(Request.Create().WithPath("/foo").WithBody((IMatcher)item[0]))
.RespondWith(Response.Create().WithBody("Hello client"));

// Act
var content = new StringContent(jsonRequestMessage, Encoding.UTF8, contentType);
var response = await new HttpClient().PostAsync("http://localhost:" + _server.Ports[0] + "/foo", content);
// Act
var content = new StringContent(jsonRequestMessage, Encoding.UTF8, (string)item[1]);
var response = await new HttpClient().PostAsync("http://localhost:" + _server.Ports[0] + "/foo", content);

// Assert
var responseString = await response.Content.ReadAsStringAsync();
Check.That(responseString).Equals("Hello client");
// Assert
var responseString = await response.Content.ReadAsStringAsync();
Check.That(responseString).Equals("Hello client");

_server.ResetMappings();
_server.ResetLogEntries();
}
}

[Fact]
Expand Down Expand Up @@ -581,24 +585,6 @@ public async Task FluentMockServer_Should_respond_to_request_callback()
Check.That(response).IsEqualTo("/fooBar");
}

[Fact]
public async Task FluentMockServer_Should_IgnoreRestrictedHeader()
{
// Assign
_server = FluentMockServer.Start();
_server
.Given(Request.Create().WithPath("/head").UsingHead())
.RespondWith(Response.Create().WithHeader("Content-Length", "1024"));

var request = new HttpRequestMessage(HttpMethod.Head, "http://localhost:" + _server.Ports[0] + "/head");

// Act
var response = await new HttpClient().SendAsync(request);

// Assert
Check.That(response.Content.Headers.GetValues("Content-Length")).ContainsExactly("0");
}

public void Dispose()
{
_server?.Stop();
Expand Down
11 changes: 7 additions & 4 deletions test/WireMock.Net.Tests/ResponseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ public class ResponseTests
{
private const string ClientIp = "::1";

[Fact]
public async void Response_Create_WithHeader_ContentLength()
[Theory]
[InlineData("Content-Length", "1024")]
[InlineData("Transfer-Encoding", "identity")]
[InlineData("Location", "http://test")]
public async void Response_Create_WithHeader(string headerName, string headerValue)
{
// Assign
var requestMock = new RequestMessage(new Uri("http://localhost/foo"), "PUT", ClientIp);
IResponseBuilder builder = Response.Create().WithHeader("Content-Length", "1024");
IResponseBuilder builder = Response.Create().WithHeader(headerName, headerValue);

// Act
var response = await builder.ProvideResponseAsync(requestMock);

// Assert
Check.That(response.Headers["Content-Length"].ToString()).Equals("1024");
Check.That(response.Headers[headerName].ToString()).Equals(headerValue);
}
}
}