diff --git a/.gitignore b/.gitignore index 81e50bb..d6c8b9c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,182 +1,41 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# DNX -project.lock.json -project.fragment.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# Web workbench (sass) -.sass-cache/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat \ No newline at end of file +*.obj +*.pdb +*.user +*.aps +*.pch +*.vspscc +*.vssscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.cache +*.ilk +*.log +*.lib +*.sbr +*.scc +[Bb]in +[Dd]ebug*/ +obj/ +[Rr]elease*/ +_ReSharper*/ +*.[Pp]ublish.xml +*.resharper* +AppData/ +App_Data/ +*.log.* +[Ll]ogs/ +[Pp]ackages/ +[Tt]humbs.db +[Tt]est[Rr]esult* +[Bb]uild[Ll]og.* +*.sln.DotSettings.* +*.ncrunchproject +*.ncrunchsolution +*.nupkg +.vs +*.orig \ No newline at end of file diff --git a/HttpClient.Helpers.nuspec b/HttpClient.Helpers.nuspec deleted file mode 100644 index 76ba7d0..0000000 --- a/HttpClient.Helpers.nuspec +++ /dev/null @@ -1,25 +0,0 @@ - - - - WorldDomination.HttpClient.Helpers - $version$ - HttpClient helpers for System.Net.Http.HttpClient - Justin Adler - Justin Adler - https://raw.githubusercontent.com/PureKrome/HttpClient.Helpers/master/LICENSE - https://github.com/PureKrome/HttpClient.Helpers - http://i.imgur.com/bR4Yf.jpg - false - Some simple System.Net.Http.HttpClient helpers to help with your unit tests or when you don't really want to call the endpoint. - Some simple System.Net.Http.HttpClient helpers. - 2014 - en-AU - httpclient worlddomination worldomination unicorn magicalunicorn magical-unicorn - - - - - - - - \ No newline at end of file diff --git a/HttpClient.Helpers.sln.DotSettings b/HttpClient.Helpers.sln.DotSettings index 355a6e9..bbea3ae 100644 --- a/HttpClient.Helpers.sln.DotSettings +++ b/HttpClient.Helpers.sln.DotSettings @@ -1,55 +1,89 @@  True True + ERROR + ERROR + ERROR + ERROR DO_NOT_SHOW DO_NOT_SHOW DO_NOT_SHOW + ERROR + ERROR + ERROR <?xml version="1.0" encoding="utf-16"?><Profile name="PK Code Cleanup"><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><HtmlReformatCode>True</HtmlReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><VBReformatCode>True</VBReformatCode><JsReformatCode>True</JsReformatCode><JsInsertSemicolon>True</JsInsertSemicolon><CssAlphabetizeProperties>True</CssAlphabetizeProperties><CssReformatCode>True</CssReformatCode><XMLReformatCode>True</XMLReformatCode><StyleCop.Documentation><SA1600ElementsMustBeDocumented>False</SA1600ElementsMustBeDocumented><SA1604ElementDocumentationMustHaveSummary>False</SA1604ElementDocumentationMustHaveSummary><SA1609PropertyDocumentationMustHaveValueDocumented>False</SA1609PropertyDocumentationMustHaveValueDocumented><SA1611ElementParametersMustBeDocumented>False</SA1611ElementParametersMustBeDocumented><SA1615ElementReturnValueMustBeDocumented>False</SA1615ElementReturnValueMustBeDocumented><SA1617VoidReturnValueMustNotBeDocumented>False</SA1617VoidReturnValueMustNotBeDocumented><SA1618GenericTypeParametersMustBeDocumented>False</SA1618GenericTypeParametersMustBeDocumented><SA1626SingleLineCommentsMustNotUseDocumentationStyleSlashes>True</SA1626SingleLineCommentsMustNotUseDocumentationStyleSlashes><SA1628DocumentationTextMustBeginWithACapitalLetter>True</SA1628DocumentationTextMustBeginWithACapitalLetter><SA1629DocumentationTextMustEndWithAPeriod>True</SA1629DocumentationTextMustEndWithAPeriod><SA1633SA1641UpdateFileHeader>Ignore</SA1633SA1641UpdateFileHeader><SA1639FileHeaderMustHaveSummary>False</SA1639FileHeaderMustHaveSummary><SA1642ConstructorSummaryDocumentationMustBeginWithStandardText>False</SA1642ConstructorSummaryDocumentationMustBeginWithStandardText><SA1643DestructorSummaryDocumentationMustBeginWithStandardText>False</SA1643DestructorSummaryDocumentationMustBeginWithStandardText><SA1644DocumentationHeadersMustNotContainBlankLines>False</SA1644DocumentationHeadersMustNotContainBlankLines></StyleCop.Documentation></Profile> PK Code Cleanup + public protected internal private new abstract virtual sealed override static readonly extern unsafe volatile async + True + True + True + True + True + True + True + True NEXT_LINE 0 NEXT_LINE + MULTILINE + True + ALWAYS_ADD NEXT_LINE + NEXT_LINE + True + NEXT_LINE DO_NOT_USE + LINE_BREAK + False + NEXT_LINE + False + CHOP_IF_LONG + CHOP_ALWAYS + True + CHOP_IF_LONG + CHOP_ALWAYS + 160 + True + CHOP_ALWAYS + CHOP_ALWAYS + CHOP_ALWAYS + CHOP_ALWAYS PBKDF <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> - + TEMP_FOLDER TEMP_FOLDER + + + + + + + True + + + + + + + True + 3 True - - - - - - - - - - - - - - - - - True True - - - - - + + + + + True True True True - 4 - True + False False True - + 4 False None False diff --git a/appveyor.yml b/appveyor.yml index 92beeb3..d7d90c7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,9 +2,7 @@ # # Current setup: # - All development is done in a fork. -# - Pull requests are merged into dev and it auto publishes -# to the myget pre-release 'pk-development' feed. -# - When publishing to master we just merge dev to master -but- no NuGet is made. +# - Pull requests are merged into master and it auto publishes to the myget pre-release 'pk-development' feed. # - To publish a live NuGet package, create a tag on master branch. # @@ -45,8 +43,6 @@ deploy: secure: 36bcjhroAjclbHs7e7oh6Hsv4lokADI6xaQcCYZmux2Sdu/IIoktFc9ORK3DTdKo skip_symbols: true artifact: /.*\.nupkg/ - on: - branch: dev - provider: NuGet api_key: secure: jfcUvHZhgnUboplqTBDWr8mG5PIlrgBv5TA2fhhop4ZSiDxskyy+RtYyeHoduJFR diff --git a/src/HttpClient.Helpers/FakeMessageHandler.cs b/src/HttpClient.Helpers/FakeMessageHandler.cs index d83e064..6ffcf34 100644 --- a/src/HttpClient.Helpers/FakeMessageHandler.cs +++ b/src/HttpClient.Helpers/FakeMessageHandler.cs @@ -13,8 +13,8 @@ public class FakeHttpMessageHandler : HttpClientHandler { private readonly HttpRequestException _exception; - private readonly IDictionary _lotsOfOptions = - new Dictionary(); + private readonly IDictionary _lotsOfOptions = new Dictionary(); + /// /// A fake message handler. @@ -22,12 +22,13 @@ public class FakeHttpMessageHandler : HttpClientHandler /// This is mainly used for unit testing purposes. /// The endpoint the HttpClient would normally try and connect to. /// The faked response message. - public FakeHttpMessageHandler(string requestUri, HttpResponseMessage httpResponseMessage) + public FakeHttpMessageHandler(string requestUri, + HttpResponseMessage httpResponseMessage) : this(new HttpMessageOptions - { - RequestUri = requestUri, - HttpResponseMessage = httpResponseMessage - }) + { + RequestUri = requestUri, + HttpResponseMessage = httpResponseMessage + }) { } @@ -50,7 +51,10 @@ public FakeHttpMessageHandler(string requestUri, HttpResponseMessage httpRespons // _responses = httpResponseMessages; //} - public FakeHttpMessageHandler(HttpMessageOptions options) : this(new List {options}) + public FakeHttpMessageHandler(HttpMessageOptions options) : this(new List + { + options + }) { } @@ -66,13 +70,15 @@ public FakeHttpMessageHandler(IDictionary responses throw new ArgumentOutOfRangeException(nameof(responses)); } - var options = responses.Select(item => new HttpMessageOptions - { - RequestUri = item.Key, - HttpResponseMessage = item.Value - }); + // NOTE: We assume HttpGet is the default when none are provided in this 'shortcut' method. + var lotsOfOptions = responses.Select(item => new HttpMessageOptions + { + RequestUri = item.Key, + HttpResponseMessage = item.Value, + HttpMethod = HttpMethod.Get + }).ToArray(); - Initialize(options.ToArray()); + Initialize(lotsOfOptions); } public FakeHttpMessageHandler(IEnumerable lotsOfOptions) @@ -87,9 +93,9 @@ public FakeHttpMessageHandler(IEnumerable lotsOfOptions) /// The faked response message. public FakeHttpMessageHandler(HttpResponseMessage httpResponseMessage) : this(new HttpMessageOptions - { - HttpResponseMessage = httpResponseMessage - }) + { + HttpResponseMessage = httpResponseMessage + }) { } @@ -115,7 +121,7 @@ public FakeHttpMessageHandler(HttpRequestException exception) /// /// protected override Task SendAsync(HttpRequestMessage request, - CancellationToken cancellationToken) + CancellationToken cancellationToken) { if (_exception != null) { @@ -124,44 +130,26 @@ protected override Task SendAsync(HttpRequestMessage reques var tcs = new TaskCompletionSource(); - HttpMessageOptions options; var requestUri = request.RequestUri.AbsoluteUri; - - // If we don't care - var uniqueKey = CreateDictionaryKey(requestUri, request.Method); - var wildcardKey = CreateDictionaryKey("*", HttpMethod.Get); - - // Determine the Response message based upon the Request uri && HttpMethod. - // 1. Exact match. - // 2. Wildcard '*' == I don't care what the Uri is, just use this Response. - // 3. Starts with == this is so we don't have to have a huge string in our test case. Just keeping code a bit cleaner. - - // 1) & 3) checks. - if (!_lotsOfOptions.TryGetValue(uniqueKey, out options) && - !_lotsOfOptions.TryGetValue(wildcardKey, out options)) + var option = new HttpMessageOptions { - // 2) Starts-with check. - foreach (var key in _lotsOfOptions.Keys.Where(uniqueKey.StartsWith)) - { - options = _lotsOfOptions[key]; - break; - } - - if (options == null) - { - // Nope - no keys found exactly OR starting-with... + RequestUri = requestUri, + HttpMethod = request.Method, + HttpContent = request.Content + }; - var responsesText = !_lotsOfOptions.Any() - ? "-none-" - : string.Join(";", _lotsOfOptions.Values); + var expectedOption = GetExpectedOption(option); + if (expectedOption == null) + { + // Nope - no keys found exactly OR starting-with... - var errorMessage = - $"No HttpResponseMessage found for the Request Uri: {request.RequestUri}. Please provide one in the FakeHttpMessageHandler constructor Or use a '*' for any request uri. Search-Key: '{requestUri}. Setup: {(!_lotsOfOptions.Any() ? "- no responses -" : _lotsOfOptions.Count.ToString())} responses: {responsesText}"; - throw new InvalidOperationException(errorMessage); - } + var responsesText = string.Join(";", _lotsOfOptions.Values); + var errorMessage = + $"No HttpResponseMessage found for the Request Uri: {request.RequestUri}. Please provide one in the FakeHttpMessageHandler constructor Or use a '*' for any request uri. Search-Key: '{requestUri}. Setup: {(!_lotsOfOptions.Any() ? "- no responses -" : _lotsOfOptions.Count.ToString())} responses: {responsesText}"; + throw new InvalidOperationException(errorMessage); } - tcs.SetResult(options.HttpResponseMessage); + tcs.SetResult(expectedOption.HttpResponseMessage); return tcs.Task; } @@ -169,8 +157,8 @@ protected override Task SendAsync(HttpRequestMessage reques /// Helper method to easily return a simple HttpResponseMessage. /// public static HttpResponseMessage GetStringHttpResponseMessage(string content, - HttpStatusCode httpStatusCode = HttpStatusCode.OK, - string mediaType = "application/json") + HttpStatusCode httpStatusCode = HttpStatusCode.OK, + string mediaType = "application/json") { return new HttpResponseMessage { @@ -179,7 +167,7 @@ public static HttpResponseMessage GetStringHttpResponseMessage(string content, }; } - private void Initialize(ICollection lotsOfOptions) + private void Initialize(HttpMessageOptions[] lotsOfOptions) { if (lotsOfOptions == null) { @@ -188,20 +176,36 @@ private void Initialize(ICollection lotsOfOptions) if (!lotsOfOptions.Any()) { - throw new ArgumentOutOfRangeException(nameof(lotsOfOptions)); + throw new ArgumentOutOfRangeException(nameof(lotsOfOptions), + "Need at least _one_ expected request/response (a.k.a. HttpMessageOptions) setup."); } + // We need to make sure the requests are unique. foreach (var option in lotsOfOptions) { - var key = CreateDictionaryKey(option.RequestUri, option.HttpMethod); - _lotsOfOptions[key] = option; + if (_lotsOfOptions.ContainsKey(option.ToString())) + { + throw new InvalidOperationException( + $"Trying to add a request/response (a.k.a. HttpMessageOptions) which has already been setup. Can only have one unique request/response, setup. Unique info: {option}"); + } + + _lotsOfOptions.Add(option.ToString(), option); } } - private static string CreateDictionaryKey(string requestUri, HttpMethod httpMethod) + private HttpMessageOptions GetExpectedOption(HttpMessageOptions option) { - var httpMethodText = httpMethod?.ToString() ?? "*"; - return $"{requestUri}||{httpMethodText}"; + if (option == null) + { + throw new ArgumentNullException(nameof(option)); + } + + return _lotsOfOptions.Values.SingleOrDefault(x => (x.RequestUri == option.RequestUri || + x.RequestUri == HttpMessageOptions.NoValue) && + (x.HttpMethod == option.HttpMethod || + x.HttpMethod == null) && + (x.HttpContent == option.HttpContent || + x.HttpContent == null)); } } } \ No newline at end of file diff --git a/src/HttpClient.Helpers/HttpClient.Helpers.csproj b/src/HttpClient.Helpers/HttpClient.Helpers.csproj index 0462cdc..e47c068 100644 --- a/src/HttpClient.Helpers/HttpClient.Helpers.csproj +++ b/src/HttpClient.Helpers/HttpClient.Helpers.csproj @@ -47,9 +47,7 @@ - - diff --git a/src/HttpClient.Helpers/HttpClientFactory.cs b/src/HttpClient.Helpers/HttpClientFactory.cs deleted file mode 100644 index cdc7e98..0000000 --- a/src/HttpClient.Helpers/HttpClientFactory.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; - -namespace WorldDomination.Net.Http -{ - public static class HttpClientFactory - { - private static readonly Lazy> MessageHandlers = - new Lazy>(); - - public static void AddMessageHandler(HttpMessageHandler messageHandler, - string key, - bool disposeHandler = true) - { - if (messageHandler == null) - { - throw new ArgumentNullException(nameof(messageHandler)); - } - - if (string.IsNullOrWhiteSpace(key)) - { - throw new ArgumentNullException(nameof(key)); - } - - if (MessageHandlers.Value.ContainsKey(key)) - { - var errorMessage = - $"Unable to add the MessageHandler instance because the key '{key}' -already- exists. Please use another key."; - throw new Exception(errorMessage); - } - - MessageHandlers.Value.Add(key, new MessageHandlerItem(messageHandler, disposeHandler)); - } - - public static void RemoveMessageHandler(string key) - { - if (string.IsNullOrWhiteSpace(key)) - { - throw new ArgumentNullException(nameof(key)); - } - - MessageHandlers.Value.Remove(key); - } - - /// - /// A normal HttpClient or one dependent upon a MessageHandler. - /// - /// Optional message handler with specific rules for this client. - /// true if the inner handler should be disposed of by Dispose(),false if you intend to reuse the inner handler. - /// - public static HttpClient GetHttpClient(HttpMessageHandler httpMessageHandler, - bool disposeHandler = true) - { - return httpMessageHandler != null - ? new HttpClient(httpMessageHandler, disposeHandler) - : new HttpClient(); - } - - /// - /// A normal HttpClient or one dependent upon a MessageHandler. - /// - /// Optional message handler with specific rules for this client. - /// - public static HttpClient GetHttpClient(string messageHandlerKey) - { - if (string.IsNullOrWhiteSpace(messageHandlerKey)) - { - throw new ArgumentNullException(nameof(messageHandlerKey)); - } - - // Determine which message handler we should use. - var httpMessageHandler = MessageHandlers.Value[messageHandlerKey]; - - // Behold! Our HttpClient instance, based on the httpMessageHandler! - return GetHttpClient(httpMessageHandler.HttpMessageHandler, httpMessageHandler.DisposeHandler); - } - } -} \ No newline at end of file diff --git a/src/HttpClient.Helpers/HttpMessageOptions.cs b/src/HttpClient.Helpers/HttpMessageOptions.cs index 03479bc..263de96 100644 --- a/src/HttpClient.Helpers/HttpMessageOptions.cs +++ b/src/HttpClient.Helpers/HttpMessageOptions.cs @@ -5,9 +5,14 @@ namespace WorldDomination.Net.Http { public class HttpMessageOptions { - private HttpMethod _httpMethod = HttpMethod.Get; - private string _requestUri = "*"; + public const string NoValue = "*"; + private HttpContent _httpContent; + private string _httpContentSerialized; + private string _requestUri = NoValue; + /// + /// Required: End url we are targetting. + /// public string RequestUri { get { return _requestUri; } @@ -16,34 +21,41 @@ public string RequestUri if (string.IsNullOrWhiteSpace(value)) { throw new ArgumentNullException(nameof(value), - "RequestUri cannot be null/empty/whitespace. Please choose a valid RequestUri."); + "RequestUri cannot be null/empty/whitespace. Please choose a valid RequestUri."); } _requestUri = value; } } - public HttpMethod HttpMethod + /// + /// Optional: If not provided, then assumed to be *any* method. + /// + public HttpMethod HttpMethod { get; set; } + + /// + /// Required: Need to know what type of response we will return. + /// + public HttpResponseMessage HttpResponseMessage { get; set; } + + /// + /// Optional: If not provided, then assumed to be *no* content. + /// + public HttpContent HttpContent { - get { return _httpMethod; } + get { return _httpContent; } set { - if (value == null) - { - throw new ArgumentNullException(nameof(value), - "HttpMethod cannot be null. Please choose a valid HttpMethod."); - } - - _httpMethod = value; + _httpContent = value; + _httpContentSerialized = _httpContent?.ReadAsStringAsync().Result ?? NoValue; } } - public HttpResponseMessage HttpResponseMessage { get; set; } - public override string ToString() { - var httpMethodText = HttpMethod?.ToString() ?? "*"; - return $"{httpMethodText} {RequestUri}"; + var httpMethodText = HttpMethod?.ToString() ?? NoValue; + return + $"{httpMethodText} {RequestUri}{(HttpContent != null ? $" body/content: {_httpContentSerialized}" : "")}"; } } } \ No newline at end of file diff --git a/src/HttpClient.Helpers/MessageHandlerItem.cs b/src/HttpClient.Helpers/MessageHandlerItem.cs deleted file mode 100644 index fe9b185..0000000 --- a/src/HttpClient.Helpers/MessageHandlerItem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Net.Http; - -namespace WorldDomination.Net.Http -{ - internal class MessageHandlerItem - { - public MessageHandlerItem(HttpMessageHandler httpMessageHandler, - bool disposeHandler) - { - if (httpMessageHandler == null) - { - throw new ArgumentNullException(nameof(httpMessageHandler)); - } - - HttpMessageHandler = httpMessageHandler; - DisposeHandler = disposeHandler; - } - - public HttpMessageHandler HttpMessageHandler { get; private set; } - public bool DisposeHandler { get; private set; } - } -} \ No newline at end of file diff --git a/tests/HttpClient.Helpers.Tests/FakeMessageHandlerFacts.cs b/tests/HttpClient.Helpers.Tests/FakeMessageHandlerFacts.cs deleted file mode 100644 index 1b68686..0000000 --- a/tests/HttpClient.Helpers.Tests/FakeMessageHandlerFacts.cs +++ /dev/null @@ -1,493 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Shouldly; -using WorldDomination.Net.Http; -using Xunit; - -// ReSharper disable ConsiderUsingConfigureAwait - -namespace WorldDomination.HttpClient.Helpers.Tests -{ - public class FakeMessageHandlerFacts - { - public class HttpMessageParameterFacts - { - [Fact] - public async Task GivenAFewHttpResponseMessages_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl1 = "http://www.something.com/some/website"; - const string responseData1 = "I am not some Html."; - var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1); - - const string requestUrl2 = "http://www.something.com/another/site"; - const string responseData2 = "Html, I am not."; - var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2); - - const string requestUrl3 = "http://www.whatever.com/"; - const string responseData3 = "pew pew"; - var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3); - - var messageResponses = new Dictionary - { - {requestUrl1, messageResponse1}, - {requestUrl2, messageResponse2}, - {requestUrl3, messageResponse3} - }; - - var messageHandler = new FakeHttpMessageHandler(messageResponses); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync(requestUrl2); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData2); - } - - [Fact] - public async Task GivenAFewHttpResponseMessagesAndTheHttpClientFactory_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl1 = "http://www.something.com/some/website"; - const string responseData1 = "I am not some Html."; - var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1); - - const string requestUrl2 = "http://www.something.com/another/site"; - const string responseData2 = "Html, I am not."; - var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2); - - const string requestUrl3 = "http://www.whatever.com/"; - const string responseData3 = "pew pew"; - var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3); - - var messageResponses = new Dictionary - { - {requestUrl1, messageResponse1}, - {requestUrl2, messageResponse2}, - {requestUrl3, messageResponse3} - }; - - var messageHandler = new FakeHttpMessageHandler(messageResponses); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync(requestUrl2); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData2); - } - - [Fact] - public async Task GivenAFewHttpResponseMessagesWithAWildcard_GetAsync_ReturnsTheWildcardResponse() - { - // Arrange. - const string requestUrl1 = "http://www.something.com/some/website"; - const string responseData1 = "I am not some Html."; - var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1); - - const string requestUrl2 = "http://www.something.com/another/site"; - const string responseData2 = "Html, I am not."; - var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2); - - const string requestUrl3 = "*"; - const string responseData3 = "pew pew"; - var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3); - - var messageResponses = new Dictionary - { - {requestUrl1, messageResponse1}, - {requestUrl2, messageResponse2}, - {requestUrl3, messageResponse3} - }; - - var messageHandler = new FakeHttpMessageHandler(messageResponses); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync("http://pewpew.com"); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData3); - } - - [Fact] - public async Task - GivenAFewHttpResponseMessagesWithAWildcardAndTheHttpClientFactory_GetAsync_ReturnsTheWildcardResponse() - { - // Arrange. - const string requestUrl1 = "http://www.something.com/some/website"; - const string responseData1 = "I am not some Html."; - var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1); - - const string requestUrl2 = "http://www.something.com/another/site"; - const string responseData2 = "Html, I am not."; - var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2); - - const string requestUrl3 = "*"; - const string responseData3 = "pew pew"; - var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3); - - var messageResponses = new Dictionary - { - {requestUrl1, messageResponse1}, - {requestUrl2, messageResponse2}, - {requestUrl3, messageResponse3} - }; - - var messageHandler = new FakeHttpMessageHandler(messageResponses); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync("http://pewpew.com"); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData3); - } - - [Fact] - public void GivenAnHttpClientException_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string errorMessage = "Oh man - something bad happened."; - var exception = new HttpRequestException(errorMessage); - var messageHandler = new FakeHttpMessageHandler(exception); - - HttpRequestException result; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - result = - Should.Throw( - async () => await httpClient.GetAsync("http://www.something.com/some/website")); - } - - // Assert. - result.Message.ShouldBe(errorMessage); - } - - [Fact] - public void GivenAnHttpClientExceptionAndTheHttpClientFactory_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string errorMessage = "Oh man - something bad happened."; - var exception = new HttpRequestException(errorMessage); - var httpMessageHandler = new FakeHttpMessageHandler(exception); - - HttpRequestException result; - using (var httpClient = HttpClientFactory.GetHttpClient(httpMessageHandler)) - { - // Act. - result = Should.Throw( - async () => await httpClient.GetAsync("http://www.something.com/some/website")); - } - - // Assert. - result.Message.ShouldBe(errorMessage); - } - - [Fact] - public async Task GivenAnHttpResponseMessage_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl = "http://www.something.com/some/website"; - const string responseData = "I am not some Html."; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - var messageHandler = new FakeHttpMessageHandler(requestUrl, messageResponse); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync(requestUrl); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - - [Fact] - public async Task GivenAnHttpResponseMessageAndNoRequestUri_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string responseData = "I am not some Html."; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - - // No RequestUri == a wildcard == any url given. - var messageHandler = new FakeHttpMessageHandler(messageResponse); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync("http://pewpew.com"); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - - [Fact] - public async Task - GivenAnHttpResponseMessageAndNoRequestUriAndTheHttpClientFactory_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string responseData = "I am not some Html."; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - - // No RequestUri == a wildcard == any url given. - var messageHandler = new FakeHttpMessageHandler(messageResponse); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync("http://pewpew.com"); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - - [Fact] - public async Task GivenAnHttpResponseMessageAndTheHttpClientFactory_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl = "http://www.something.com/some/website"; - const string responseData = "I am not some Html."; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - var messageHandler = new FakeHttpMessageHandler(requestUrl, messageResponse); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync(requestUrl); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - - [Fact] - public async Task GivenAnHttpVerb_DeleteAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl = "http://www.something.com/some/website"; - const string responseData = "Delete me plz"; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - var options = new HttpMessageOptions - { - RequestUri = requestUrl, - HttpMethod = HttpMethod.Delete, - HttpResponseMessage = messageResponse - }; - var messageHandler = new FakeHttpMessageHandler(options); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.DeleteAsync(requestUrl); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - - [Fact] - public void GivenAnInvalidHttpVerb_GetAsync_ThrowsAnException() - { - // Arrange. - const string requestUrl = "http://www.something.com/some/website"; - const string responseData = "Delete me plz"; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - var options = new HttpMessageOptions - { - RequestUri = requestUrl, - HttpMethod = HttpMethod.Delete, - HttpResponseMessage = messageResponse - }; - var messageHandler = new FakeHttpMessageHandler(options); - - Exception exception; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - exception = Should.Throw(() => httpClient.GetAsync(requestUrl)); - } - - // Assert. - exception.Message.ShouldBe( - $"No HttpResponseMessage found for the Request Uri: {requestUrl}. Please provide one in the FakeHttpMessageHandler constructor Or use a '*' for any request uri. Search-Key: '{requestUrl}. Setup: 1 responses: DELETE {requestUrl}"); - } - - [Fact] - public async Task GivenAnRequestUrlWithEncodedJson_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - var requestUri = new Uri("http://www.whatever.com/something?json=%7B%0A%20%20%20%22Ids%22%3A%20%5B16036%2C1%5D%0A%7D"); - const string responseData = "I am not some Html."; - var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - - var messageResponses = new Dictionary - { - {requestUri.AbsoluteUri, messageResponse1}, - }; - - var messageHandler = new FakeHttpMessageHandler(messageResponses); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(messageHandler)) - { - // Act. - message = await httpClient.GetAsync(requestUri); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - } - - public class AddMessageFacts - { - [Fact] - public async Task GivenAFewHttpResponseMessages_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl1 = "http://www.something.com/some/website"; - const string responseData1 = "I am not some Html."; - var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1); - - const string requestUrl2 = "http://www.something.com/another/site"; - const string responseData2 = "Html, I am not."; - var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2); - - const string requestUrl3 = "http://www.whatever.com/"; - const string responseData3 = "pew pew"; - var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3); - - var messageResponses = new Dictionary - { - {requestUrl1, messageResponse1}, - {requestUrl2, messageResponse2}, - {requestUrl3, messageResponse3} - }; - - var messageHandler = new FakeHttpMessageHandler(messageResponses); - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key: key); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - // Act. - message = await httpClient.GetAsync(requestUrl2); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData2); - } - - [Fact] - public async Task GivenAnHttpResponseMessage_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl = "http://www.something.com/some/website"; - const string responseData = "I am not some Html."; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - var messageHandler = new FakeHttpMessageHandler(requestUrl, messageResponse); - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key: key); - - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - // Act. - message = await httpClient.GetAsync(requestUrl); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - - [Fact] - public async Task GivenAnHttpResponseMessageAndTheHttpClientFactory_GetAsync_ReturnsAFakeResponse() - { - // Arrange. - const string requestUrl = "http://www.something.com/some/website"; - const string responseData = "I am not some Html."; - var messageResponse = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData); - var messageHandler = new FakeHttpMessageHandler(requestUrl, messageResponse); - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key: key); - HttpResponseMessage message; - string content; - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - // Act. - message = await httpClient.GetAsync(requestUrl); - content = await message.Content.ReadAsStringAsync(); - } - - // Assert. - message.StatusCode.ShouldBe(HttpStatusCode.OK); - content.ShouldBe(responseData); - } - } - } -} \ No newline at end of file diff --git a/tests/HttpClient.Helpers.Tests/GetAsyncTests.cs b/tests/HttpClient.Helpers.Tests/GetAsyncTests.cs new file mode 100644 index 0000000..c4bcec3 --- /dev/null +++ b/tests/HttpClient.Helpers.Tests/GetAsyncTests.cs @@ -0,0 +1,203 @@ +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Shouldly; +using WorldDomination.Net.Http; +using Xunit; + +// ReSharper disable ConsiderUsingConfigureAwait + +namespace WorldDomination.HttpClient.Helpers.Tests +{ + public class GetAsyncTests + { + private const string RequestUri = "http://www.something.com/some/website"; + private const string ExpectedContent = "pew pew"; + + private static List GetSomeFakeHttpMessageOptions(HttpMessageOptions option) + { + return new List + { + new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + RequestUri = "http://some/url", + HttpResponseMessage = SomeFakeResponse + }, + new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + RequestUri = "http://another/url", + HttpResponseMessage = SomeFakeResponse + }, + option + }; + } + + private static HttpResponseMessage SomeFakeResponse => new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(ExpectedContent) + }; + + public static IEnumerable ValidHttpMessageOptions + { + get + { + yield return new object[] + { + // All wildcards. + new HttpMessageOptions + { + HttpResponseMessage = SomeFakeResponse + } + }; + + // Any Uri but has to be a GET. + yield return new object[] + { + new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + HttpResponseMessage = SomeFakeResponse + } + }; + + // Has to match GET + URI. + // NOTE: Http GET shouldn't have a content/body. + yield return new object[] + { + new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + RequestUri = RequestUri, + HttpResponseMessage = SomeFakeResponse + } + }; + } + } + + public static IEnumerable ValidSomeHttpMessageOptions + { + get + { + yield return new object[] + { + // All wildcards. + GetSomeFakeHttpMessageOptions( + new HttpMessageOptions + { + HttpResponseMessage = SomeFakeResponse + }) + }; + + yield return new object[] + { + // All wildcards. + GetSomeFakeHttpMessageOptions( + new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + HttpResponseMessage = SomeFakeResponse + }) + }; + + yield return new object[] + { + // All wildcards. + GetSomeFakeHttpMessageOptions( + new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + RequestUri = RequestUri, + HttpResponseMessage = SomeFakeResponse + }) + }; + } + } + + [Theory] + [MemberData(nameof(ValidHttpMessageOptions))] + public async Task GivenAnHttpMessageOptions_GetAsync_ReturnsAFakeResponse(HttpMessageOptions option) + { + var fakeHttpMessageHandler = new FakeHttpMessageHandler(option); + + await DoGetAsync(RequestUri, + ExpectedContent, + fakeHttpMessageHandler); + } + + [Theory] + [MemberData(nameof(ValidSomeHttpMessageOptions))] + public async Task GivenSomeHttpMessageOptions_GetAsync_ReturnsAFakeResponse(IEnumerable lotsOfOption) + { + var fakeHttpMessageHandler = new FakeHttpMessageHandler(lotsOfOption); + + await DoGetAsync(RequestUri, + ExpectedContent, + fakeHttpMessageHandler); + } + + private static async Task DoGetAsync(string requestUri, + string expectedResponseContent, + FakeHttpMessageHandler fakeHttpMessageHandler) + { + requestUri.ShouldNotBeNullOrWhiteSpace(); + expectedResponseContent.ShouldNotBeNullOrWhiteSpace(); + fakeHttpMessageHandler.ShouldNotBeNull(); + + HttpResponseMessage message; + string content; + using (var httpClient = new System.Net.Http.HttpClient(fakeHttpMessageHandler)) + { + // Act. + message = await httpClient.GetAsync(requestUri); + content = await message.Content.ReadAsStringAsync(); + } + + // Assert. + message.StatusCode.ShouldBe(HttpStatusCode.OK); + content.ShouldBe(expectedResponseContent); + } + + [Fact] + public async Task GivenAnHttpResponseMessage_GetAsync_ReturnsAFakeResponse() + { + var httpResponseMessage = FakeHttpMessageHandler.GetStringHttpResponseMessage(ExpectedContent); + var fakeHttpMessageHandler = new FakeHttpMessageHandler(httpResponseMessage); + + await DoGetAsync(RequestUri, + ExpectedContent, + fakeHttpMessageHandler); + } + + [Fact] + public async Task GivenSomeHttpResponseMessages_GetAsync_ReturnsAFakeResponse() + { + const string requestUrl1 = RequestUri; + const string responseData1 = ExpectedContent; + var messageResponse1 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData1); + + const string requestUrl2 = "http://www.something.com/another/site"; + const string responseData2 = "Html, I am not."; + var messageResponse2 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData2); + + const string requestUrl3 = "http://www.whatever.com/"; + const string responseData3 = "pew pew"; + var messageResponse3 = FakeHttpMessageHandler.GetStringHttpResponseMessage(responseData3); + + var messageResponses = new Dictionary + { + {requestUrl1, messageResponse1}, + {requestUrl2, messageResponse2}, + {requestUrl3, messageResponse3} + }; + + var fakeHttpMessageHandler = new FakeHttpMessageHandler(messageResponses); + + await DoGetAsync(RequestUri, + ExpectedContent, + fakeHttpMessageHandler); + } + } +} \ No newline at end of file diff --git a/tests/HttpClient.Helpers.Tests/GetStringAsyncTests.cs b/tests/HttpClient.Helpers.Tests/GetStringAsyncTests.cs new file mode 100644 index 0000000..caedf22 --- /dev/null +++ b/tests/HttpClient.Helpers.Tests/GetStringAsyncTests.cs @@ -0,0 +1,43 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Shouldly; +using WorldDomination.Net.Http; +using Xunit; + +// ReSharper disable ConsiderUsingConfigureAwait + +namespace WorldDomination.HttpClient.Helpers.Tests +{ + public class GetStringAsyncTests + { + [Fact] + public async Task GivenARequest_GetStringAsync_ReturnsAFakeResponse() + { + // Arrange. + const string requestUri = "http://www.something.com/some/website"; + const string responseContent = "hi"; + var options = new HttpMessageOptions + { + HttpMethod = HttpMethod.Get, + RequestUri = requestUri, + HttpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(responseContent) + } + }; + + var messageHandler = new FakeHttpMessageHandler(options); + + string content; + using (var httpClient = new System.Net.Http.HttpClient(messageHandler)) + { + // Act. + content = await httpClient.GetStringAsync(requestUri); + } + + // Assert. + content.ShouldBe(responseContent); + } + } +} \ No newline at end of file diff --git a/tests/HttpClient.Helpers.Tests/HttpClient.Helpers.Tests.csproj b/tests/HttpClient.Helpers.Tests/HttpClient.Helpers.Tests.csproj index 1793687..2c5f3a3 100644 --- a/tests/HttpClient.Helpers.Tests/HttpClient.Helpers.Tests.csproj +++ b/tests/HttpClient.Helpers.Tests/HttpClient.Helpers.Tests.csproj @@ -63,8 +63,9 @@ - - + + + @@ -76,6 +77,9 @@ HttpClient.Helpers + + + diff --git a/tests/HttpClient.Helpers.Tests/IntegrationFacts.cs b/tests/HttpClient.Helpers.Tests/IntegrationFacts.cs deleted file mode 100644 index 3059c9f..0000000 --- a/tests/HttpClient.Helpers.Tests/IntegrationFacts.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Shouldly; -using WorldDomination.Net.Http; -using Xunit; -// ReSharper disable ConsiderUsingConfigureAwait - -namespace WorldDomination.HttpClient.Helpers.Tests -{ - public class IntegrationFacts - { - public class AddMessageHandlerFacts - { - [Fact] - public async Task GivenAGetRequest_GetStringAsync_ReturnsSomeData() - { - // Arrange. - string html; - - var messageHandler = new HttpClientHandler - { - Credentials = new NetworkCredential("api", "hi there!") - }; - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key); - - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - html = await httpClient.GetStringAsync("http://www.google.com.au"); - } - - // Assert. - html.ShouldNotBeNullOrEmpty(); - } - - [Fact] - public async Task GivenTwoGetRequests_GetStringAsync_ReturnsSomeData() - { - // Arrange. - string html1, html2; - - var messageHandler = new HttpClientHandler - { - Credentials = new NetworkCredential("api", "hi there!") - }; - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key, false); - - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - html1 = await httpClient.GetStringAsync("http://www.google.com.au"); - } - - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - html2 = await httpClient.GetStringAsync("http://www.google.com.au"); - } - - // Assert. - html1.ShouldNotBeNullOrEmpty(); - html2.ShouldNotBeNullOrEmpty(); - } - - [Fact] - public async Task GivenTwoGetRequestsButFailedToReuseHandler_GetStringAsync_ShouldThrowAnException() - { - // Arrange. - string html1; - - var messageHandler = new HttpClientHandler - { - Credentials = new NetworkCredential("api", "hi there!") - }; - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key); // Handler is disposed after first used. - - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - html1 = await httpClient.GetStringAsync("http://www.google.com.au"); - } - - Exception exception; - using (var httpClient = HttpClientFactory.GetHttpClient(key)) - { - var client = httpClient; - exception = Should.Throw( - async () => await client.GetStringAsync("http://www.google.com.au")); - } - - // Assert. - html1.ShouldNotBeNullOrEmpty(); - exception.Message.ShouldStartWith("Cannot access a disposed object."); - } - } - - public class RemoveMessageHanderFacts - { - [Fact] - public void GivenAMessageHandlerExists_RemoveMessageHandler_Succeeds() - { - // Arrange. - var messageHandler = new HttpClientHandler - { - Credentials = new NetworkCredential("api", "hi there!") - }; - - var key = Guid.NewGuid().ToString(); - HttpClientFactory.AddMessageHandler(messageHandler, key); - - // Act & Assert. - HttpClientFactory.RemoveMessageHandler(key); - } - - [Fact] - public void GivenAMessageHandlerExistsByADifferentKeyIsProvided_RemoveMessageHandler_Succeeds() - { - // Arrange. - var messageHandler = new HttpClientHandler - { - Credentials = new NetworkCredential("api", "hi there!") - }; - - HttpClientFactory.AddMessageHandler(messageHandler, Guid.NewGuid().ToString()); - - // Act & Assert. - HttpClientFactory.RemoveMessageHandler(Guid.NewGuid().ToString()); - } - - [Fact] - public void GivenNoMessageHandlerExists_RemoveMessageHandler_Succeeds() - { - // Arrange. - var key = Guid.NewGuid().ToString(); - - // Act & Assert. - HttpClientFactory.RemoveMessageHandler(key); - } - } - - public class HttpMessageParameterFacts - { - [Fact] - public async Task GivenAGetRequestAndDifferentNetworkCredentials_GetStringAsync_ReturnsSomeData() - { - // Arrange. - string html1, html2; - - var credentials1 = new HttpClientHandler - { - Credentials = new NetworkCredential("api", "hi there!") - }; - var credentials2 = new HttpClientHandler - { - Credentials = new NetworkCredential("cccc", "ddddd") - }; - - // Act. - using (var httpClient = HttpClientFactory.GetHttpClient(credentials1)) - { - html1 = await httpClient.GetStringAsync("http://www.google.com.au"); - } - - using (var httpClient = HttpClientFactory.GetHttpClient(credentials2)) - { - html2 = await httpClient.GetStringAsync("http://www.google.com.au"); - } - - // Assert. - html1.ShouldNotBeNullOrEmpty(); - html2.ShouldNotBeNullOrEmpty(); - } - } - } -} \ No newline at end of file diff --git a/tests/HttpClient.Helpers.Tests/PostAsyncTests.cs b/tests/HttpClient.Helpers.Tests/PostAsyncTests.cs new file mode 100644 index 0000000..4c7a915 --- /dev/null +++ b/tests/HttpClient.Helpers.Tests/PostAsyncTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Shouldly; +using WorldDomination.Net.Http; +using Xunit; + +// ReSharper disable ConsiderUsingConfigureAwait + +namespace WorldDomination.HttpClient.Helpers.Tests +{ + public class PostAsyncTests + { + public static IEnumerable ValidPostHttpContent + { + get + { + yield return new object[] + { + // Sample json. + new StringContent("{\"id\":1}", Encoding.UTF8) + }; + + yield return new object[] + { + // Form key/values. + new FormUrlEncodedContent(new[] + { + new KeyValuePair("a", "b"), + new KeyValuePair("c", "1") + }) + }; + } + } + + public static IEnumerable InvalidPostHttpContent + { + get + { + yield return new object[] + { + // Sample json. + new StringContent("{\"id\":1}", Encoding.UTF8), + new StringContent("{\"id\":2}", Encoding.UTF8) + }; + + yield return new object[] + { + // Form key/values. + new FormUrlEncodedContent(new[] + { + new KeyValuePair("a", "b"), + new KeyValuePair("c", "1") + }), + new FormUrlEncodedContent(new[] + { + new KeyValuePair("2", "1") + }) + }; + } + } + + [Theory] + [MemberData(nameof(ValidPostHttpContent))] + public async Task GivenAPostRequest_PostAsync_ReturnsAFakeResponse(HttpContent httpContent) + { + // Arrange. + const string requestUri = "http://www.something.com/some/website"; + const string responseContent = "hi"; + var options = new HttpMessageOptions + { + HttpMethod = HttpMethod.Post, + RequestUri = requestUri, + HttpContent = httpContent, + HttpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(responseContent) + } + }; + + var messageHandler = new FakeHttpMessageHandler(options); + + HttpResponseMessage message; + string content; + using (var httpClient = new System.Net.Http.HttpClient(messageHandler)) + { + // Act. + message = await httpClient.PostAsync(requestUri, httpContent); + content = await message.Content.ReadAsStringAsync(); + } + + // Assert. + message.StatusCode.ShouldBe(HttpStatusCode.OK); + content.ShouldBe(responseContent); + } + + [Theory] + [MemberData(nameof(InvalidPostHttpContent))] + public async Task GivenAPostRequestWithIncorrectlySetupOptions_PostAsync_ThrowsAnException(HttpContent expectedHttpContent, + HttpContent sentHttpContent) + { + // Arrange. + const string responseContent = "hi"; + var options = new HttpMessageOptions + { + HttpMethod = HttpMethod.Post, + RequestUri = "http://www.something.com/some/website", + HttpContent = expectedHttpContent, + HttpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(responseContent) + } + }; + + var messageHandler = new FakeHttpMessageHandler(options); + InvalidOperationException exception; + using (var httpClient = new System.Net.Http.HttpClient(messageHandler)) + { + // Act. + exception = + await + Should.ThrowAsync( + async () => await httpClient.PostAsync("http://www.something.com/some/website", sentHttpContent)); + } + + // Assert. + exception.Message.ShouldStartWith("No HttpResponseMessage found"); + } + } +} \ No newline at end of file