From f3128cffe068a60ea267a96b6c3f79c141c42f42 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Wed, 14 Sep 2016 21:18:25 +0100 Subject: [PATCH] failing pesky test --- .../Requester/HttpClientHttpRequester.cs | 26 ++- .../Requester/IHttpRequester.cs | 9 +- .../Middleware/ProxyMiddleware.cs | 4 +- test/Ocelot.AcceptanceTests/OcelotTests.cs | 10 +- .../Requester/RequesterTests.cs | 160 +++++++++++++++++- 5 files changed, 203 insertions(+), 6 deletions(-) diff --git a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs index 0f3bbbec..a43f4f8b 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/HttpClientHttpRequester.cs @@ -1,17 +1,39 @@ using System.IO; using System.Net.Http; using System.Threading.Tasks; +using Flurl; using Flurl.Http; +using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Requester { public class HttpClientHttpRequester : IHttpRequester { - public async Task GetResponse(string httpMethod, string downstreamUrl, Stream content = null) + public async Task GetResponse( + string httpMethod, + string downstreamUrl, + Stream content, + IHeaderDictionary headers, + IRequestCookieCollection cookies, + IQueryCollection queryString) { var method = new HttpMethod(httpMethod); + var streamContent = new StreamContent(content); - return await downstreamUrl.SendAsync(method, new StreamContent(content)); + if (content.Length > 0) + { + return await downstreamUrl + .SetQueryParams(queryString) + .WithCookies(cookies) + .WithHeaders(streamContent.Headers) + .SendAsync(method, streamContent); + } + + return await downstreamUrl + .SetQueryParams(queryString) + .WithHeaders(headers) + .WithCookies(cookies) + .SendAsync(method, streamContent); } } } \ No newline at end of file diff --git a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs index 9d38cc25..90ff384a 100644 --- a/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs +++ b/src/Ocelot.Library/Infrastructure/Requester/IHttpRequester.cs @@ -2,11 +2,18 @@ using System.Net.Http; using System.Threading.Tasks; using Flurl.Http; +using Microsoft.AspNetCore.Http; namespace Ocelot.Library.Infrastructure.Requester { public interface IHttpRequester { - Task GetResponse(string httpMethod, string downstreamUrl, Stream content = null); + Task GetResponse( + string httpMethod, + string downstreamUrl, + Stream content, + IHeaderDictionary headers, + IRequestCookieCollection cookies, + IQueryCollection queryString); } } diff --git a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs index 9eb93e07..8749ac29 100644 --- a/src/Ocelot.Library/Middleware/ProxyMiddleware.cs +++ b/src/Ocelot.Library/Middleware/ProxyMiddleware.cs @@ -47,7 +47,9 @@ namespace Ocelot.Library.Middleware var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); - var response = await _requester.GetResponse(context.Request.Method, downstreamUrl, context.Request.Body); + var response = await _requester + .GetResponse(context.Request.Method, downstreamUrl, context.Request.Body, + context.Request.Headers, context.Request.Cookies, context.Request.Query); await _responder.CreateResponse(context, response); diff --git a/test/Ocelot.AcceptanceTests/OcelotTests.cs b/test/Ocelot.AcceptanceTests/OcelotTests.cs index 41911a4d..427dab0e 100644 --- a/test/Ocelot.AcceptanceTests/OcelotTests.cs +++ b/test/Ocelot.AcceptanceTests/OcelotTests.cs @@ -21,6 +21,7 @@ namespace Ocelot.AcceptanceTests private HttpClient _client; private HttpResponseMessage _response; private readonly string _configurationPath; + private string _postContent; public OcelotTests() { @@ -76,11 +77,17 @@ namespace Ocelot.AcceptanceTests } })) .And(x => x.GivenTheApiGatewayIsRunning()) + .And(x => x.GivenThePostHasContent("postContent")) .When(x => x.WhenIPostUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } + private void GivenThePostHasContent(string postcontent) + { + _postContent = postcontent; + } + /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// @@ -119,7 +126,8 @@ namespace Ocelot.AcceptanceTests private void WhenIPostUrlOnTheApiGateway(string url) { - _response = _client.PostAsync(url, new StringContent(string.Empty)).Result; + var content = new StringContent(_postContent); + _response = _client.PostAsync(url, content).Result; } private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) diff --git a/test/Ocelot.UnitTests/Requester/RequesterTests.cs b/test/Ocelot.UnitTests/Requester/RequesterTests.cs index dd9d86d4..64785665 100644 --- a/test/Ocelot.UnitTests/Requester/RequesterTests.cs +++ b/test/Ocelot.UnitTests/Requester/RequesterTests.cs @@ -1,9 +1,14 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; using Flurl.Http.Testing; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Internal; +using Microsoft.Extensions.Primitives; using Ocelot.Library.Infrastructure.Requester; using Shouldly; using TestStack.BDDfy; @@ -19,6 +24,9 @@ namespace Ocelot.UnitTests.Requester private string _downstreamUrl; private HttpResponseMessage _result; private HttpContent _content; + private IHeaderDictionary _headers; + private IRequestCookieCollection _cookies; + private IQueryCollection _query; public RequesterTests() { @@ -66,6 +74,153 @@ namespace Ocelot.UnitTests.Requester .BDDfy(); } + [Fact] + public void should_forward_http_content_headers() + { + this.Given(x => x.GivenIHaveHttpMethod("POST")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenIHaveTheHttpContent(new StringContent("Hi from Tom") + { + Headers = + { + {"Boom", "TickTick"} + } + })) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectHttpMethodIsUsed(HttpMethod.Post)) + .And(x => x.ThenTheCorrectContentIsUsed(new StringContent("Hi from Tom") + { + Headers = + { + { "Boom", "TickTick" } + } + })) + .And(x => x.ThenTheCorrectContentHeadersAreUsed(new HeaderDictionary + { + { + "Boom", "TickTick" + } + })) + .BDDfy(); + } + + [Fact] + public void should_forward_headers() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheHttpHeadersAre(new HeaderDictionary + { + {"ChopSticks", "Bubbles" } + })) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectHeadersAreUsed(new HeaderDictionary + { + {"ChopSticks", "Bubbles" } + })) + .BDDfy(); + } + + [Fact] + public void should_forward_cookies() + { + this.Given(x => x.GivenIHaveHttpMethod("GET")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheCookiesAre(new RequestCookieCollection(new Dictionary + { + { "TheCookie","Monster" } + }))) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.OK)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.OK)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectCookiesAreUsed(new RequestCookieCollection(new Dictionary + { + { "TheCookie","Monster" } + }))) + .BDDfy(); + } + + [Fact] + public void should_forward_query_string() + { + this.Given(x => x.GivenIHaveHttpMethod("POST")) + .And(x => x.GivenIHaveDownstreamUrl("http://www.bbc.co.uk")) + .And(x => x.GivenTheQueryStringIs(new QueryCollection(new Dictionary + { + { "jeff", "1" }, + { "geoff", "2" } + }))) + .And(x => x.GivenTheDownstreamServerReturns(HttpStatusCode.Created)) + .When(x => x.WhenIMakeARequest()) + .Then(x => x.ThenTheFollowingIsReturned(HttpStatusCode.Created)) + .And(x => x.ThenTheDownstreamServerIsCalledCorrectly()) + .And(x => x.ThenTheCorrectQueryStringIsUsed("?jeff=1&geoff=2")) + .BDDfy(); + } + + private void ThenTheCorrectQueryStringIsUsed(string expected) + { + _httpTest.CallLog[0].Request.RequestUri.Query.ShouldBe(expected); + } + + private void GivenTheQueryStringIs(IQueryCollection query) + { + _query = query; + } + + private void ThenTheCorrectCookiesAreUsed(IRequestCookieCollection cookies) + { + var expectedCookies = cookies.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedCookie in expectedCookies) + { + _httpTest + .CallLog[0] + .Request + .Headers + .ShouldContain(x => x.Key == "Cookie" && x.Value.First() == string.Format("{0}={1}", expectedCookie.Key, expectedCookie.Value)); + } + } + + private void GivenTheCookiesAre(IRequestCookieCollection cookies) + { + _cookies = cookies; + } + + private void ThenTheCorrectHeadersAreUsed(IHeaderDictionary headers) + { + var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedHeader in expectedHeaders) + { + _httpTest.CallLog[0].Request.Headers.ShouldContain(x => x.Key == expectedHeader.Key && x.Value.First() == expectedHeader.Value[0]); + } + } + + private void ThenTheCorrectContentHeadersAreUsed(IHeaderDictionary headers) + { + var expectedHeaders = headers.Select(x => new KeyValuePair(x.Key, x.Value)); + + foreach (var expectedHeader in expectedHeaders) + { + _httpTest.CallLog[0].Request.Content.Headers.ShouldContain(x => x.Key == expectedHeader.Key + //&& x.Value.First() == expectedHeader.Value[0] + ); + } + } + + private void GivenTheHttpHeadersAre(IHeaderDictionary headers) + { + _headers = headers; + } + private void GivenIHaveTheHttpContent(HttpContent content) { _content = content; @@ -88,7 +243,10 @@ namespace Ocelot.UnitTests.Requester private void WhenIMakeARequest() { - _result = _httpRequester.GetResponse(_httpMethod, _downstreamUrl, _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null).Result; + _result = _httpRequester + .GetResponse(_httpMethod, _downstreamUrl, + _content != null ? _content.ReadAsStreamAsync().Result : Stream.Null, + _headers, _cookies, _query).Result; } private void ThenTheFollowingIsReturned(HttpStatusCode expected)