diff --git a/Directory.Build.props b/Directory.Build.props index abb452e..eee5155 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 0.2.9 + 0.2.11 \ No newline at end of file diff --git a/src/QAToolKit.Engine.HttpTester.Test/Fixtures/BicycleFixture.cs b/src/QAToolKit.Engine.HttpTester.Test/Fixtures/BicycleFixture.cs index 671dccf..a044426 100644 --- a/src/QAToolKit.Engine.HttpTester.Test/Fixtures/BicycleFixture.cs +++ b/src/QAToolKit.Engine.HttpTester.Test/Fixtures/BicycleFixture.cs @@ -15,6 +15,31 @@ public static Bicycle Get() }; } + public static Bicycle GetCannondale() + { + return new Bicycle + { + Id = 2, + Name = "CAADX", + Brand = "Cannondale", + Type = BicycleType.Gravel + }; + } + + public static List GetCannondaleArray() + { + return new List() + { + new Bicycle() + { + Id = 2, + Name = "CAADX", + Brand = "Cannondale", + Type = BicycleType.Gravel + } + }; + } + public static Bicycle GetFoil() { return new Bicycle diff --git a/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs b/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs index b52d28b..9b08823 100644 --- a/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs +++ b/src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs @@ -31,7 +31,7 @@ public async Task HttpTestAsserterSimple_Success() var duration = client.Duration; var assertResults = asserter .ResponseContentContains("scott") - .RequestDurationEquals(duration, (x) => x < 1000) + .RequestDurationEquals(duration, (x) => x < 2000) .ResponseStatusCodeEquals(HttpStatusCode.OK) .ResponseHasHttpHeader("Date") .AssertAll(); @@ -116,7 +116,7 @@ public async Task HttpTestAsserterHeaderMissing_Fails() var duration = client.Duration; Assert.Throws(() => asserter .ResponseContentContains("scott") - .RequestDurationEquals(duration, (x) => x < 1000) + .RequestDurationEquals(duration, (x) => x < 2000) .ResponseStatusCodeEquals(HttpStatusCode.OK) .ResponseHasHttpHeader(null) .AssertAll()); diff --git a/src/QAToolKit.Engine.HttpTester.Test/HttpTesterClientTests.cs b/src/QAToolKit.Engine.HttpTester.Test/HttpTesterClientTests.cs index c53b0ad..0b59a8f 100644 --- a/src/QAToolKit.Engine.HttpTester.Test/HttpTesterClientTests.cs +++ b/src/QAToolKit.Engine.HttpTester.Test/HttpTesterClientTests.cs @@ -548,7 +548,7 @@ public void HttpTesterClientBrochureUploadMultipartPresent_Fails() .WithMultipart("Metadata.Year", "2000") .WithMultipart("Metadata.Name", "Brochure 2000"); - var exception = Assert.Throws(() => client.WithJsonBody("1234")); + var exception = Assert.Throws(() => client.WithJsonBody("1234")); Assert.StartsWith("Body multipart/form-data already defined", exception.Message); } } @@ -617,5 +617,74 @@ public async Task HttpTesterClientAddGetHttpRequest_Success() Assert.True(response.IsSuccessStatusCode); } } + + [Fact] + public async Task HttpTesterClientGetBikeByIdRequest_Success() + { + var urlSource = new SwaggerUrlSource(options => + { + options.AddBaseUrl(new Uri("https://qatoolkitapi.azurewebsites.net/")); + options.AddRequestFilters(new RequestFilter() + { + EndpointNameWhitelist = new string[] { "GetBike" } + }); + options.UseSwaggerExampleValues = true; + }); + + var requests = await urlSource.Load(new Uri[] { + new Uri("https://qatoolkitapi.azurewebsites.net/swagger/v2/swagger.json") + }); + + using (var client = new HttpTesterClient()) + { + var response = await client + .CreateHttpRequest(requests.FirstOrDefault()) + .WithPathReplacementValues(new Dictionary() { { "id", "2" } }) + .WithQueryParams(new Dictionary() { { "api-version", "2" } }) + .Start(); + + var msg = await response.GetResponseBody(); + + var expecterResponse = BicycleFixture.GetCannondale().ToExpectedObject(); + expecterResponse.ShouldEqual(msg); + + Assert.True(client.Duration < 2000); + Assert.True(response.IsSuccessStatusCode); + } + } + + [Fact] + public async Task HttpTesterClientGetBikesByTypeHttpRequest_Success() + { + var urlSource = new SwaggerUrlSource(options => + { + options.AddBaseUrl(new Uri("https://qatoolkitapi.azurewebsites.net/")); + options.AddRequestFilters(new RequestFilter() + { + EndpointNameWhitelist = new string[] { "GetAllBikes" } + }); + options.UseSwaggerExampleValues = true; + }); + + var requests = await urlSource.Load(new Uri[] { + new Uri("https://qatoolkitapi.azurewebsites.net/swagger/v2/swagger.json") + }); + + using (var client = new HttpTesterClient()) + { + var response = await client + .CreateHttpRequest(requests.FirstOrDefault()) + .WithQueryParams(new Dictionary() { { "api-version", "2" }, {"bicycleType", "1" } }) + .Start(); + + var msg = await response.GetResponseBody>(); + + var expecterResponse = BicycleFixture.GetCannondaleArray().ToExpectedObject(); + expecterResponse.ShouldEqual(msg); + + Assert.True(client.Duration < 2000); + Assert.True(response.IsSuccessStatusCode); + } + } } } diff --git a/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs b/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs index 21dae33..6564097 100644 --- a/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs +++ b/src/QAToolKit.Engine.HttpTester/HttpTestAsserter.cs @@ -3,7 +3,6 @@ using QAToolKit.Engine.HttpTester.Models; using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Http; @@ -97,7 +96,7 @@ public IHttpTestAsserter ResponseHasHttpHeader(string headerName) Name = nameof(ResponseHasHttpHeader), Message = $"Contains header '{headerName}'.", IsTrue = _httpResponseMessage.Headers.TryGetValues(headerName, out var values) - }); + }); return this; } diff --git a/src/QAToolKit.Engine.HttpTester/HttpTesterClient.cs b/src/QAToolKit.Engine.HttpTester/HttpTesterClient.cs index 0c0b729..b2f305d 100644 --- a/src/QAToolKit.Engine.HttpTester/HttpTesterClient.cs +++ b/src/QAToolKit.Engine.HttpTester/HttpTesterClient.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Linq; using System.Net; using System.Net.Http; @@ -67,6 +66,69 @@ public IHttpTesterClient CreateHttpRequest(Uri baseAddress, bool validateCertifi return this; } + /// + /// Create a HTTP tester client from QAToolKit HttpRequest object + /// + /// Create tester client with BaseUrl, Path, HttpMethod, Headers and URL Query paramteres read from HttpRequest object. Specify other values and parameters manually. + /// + /// + public IHttpTesterClient CreateHttpRequest(HttpRequest httpRequest, bool validateCertificate = true) + { + if (httpRequest == null) + throw new QAToolKitEngineHttpTesterException("'HttpRequest' is null. Pass in the valid object."); + if (HttpClient != null) + throw new QAToolKitEngineHttpTesterException("HttpClient is already instantiated. Create new 'HttpTesterClient'."); + + var baseAddress = new Uri(httpRequest.BasePath); + + HttpHandler = new HttpClientHandler(); + + if (!validateCertificate && + (baseAddress.Scheme == Uri.UriSchemeHttp || baseAddress.Scheme == Uri.UriSchemeHttps)) + { + HttpHandler.ClientCertificateOptions = ClientCertificateOption.Manual; + HttpHandler.ServerCertificateCustomValidationCallback = + (httpRequestMessage, cert, cetChain, policyErrors) => + { + return true; + }; + } + + HttpClient = new HttpClient(HttpHandler) + { + BaseAddress = baseAddress + }; + + if (string.IsNullOrEmpty(httpRequest.Path)) + { + throw new QAToolKitEngineHttpTesterException("HttpRequest Path is required."); + } + + _path = httpRequest.Path; + + _httpMethod = httpRequest.Method; + + //Query parameters + if (_queryParameters == null) + _queryParameters = new Dictionary(); + + foreach (var parameter in httpRequest.Parameters.Where(t => t.Location == Location.Query && t.Value != null)) + { + _queryParameters.Add(parameter.Name, parameter.Value); + } + + //Headers + if (_headers == null) + _headers = new Dictionary(); + + foreach (var header in httpRequest.Parameters.Where(t => t.Location == Location.Header && t.Value != null)) + { + _headers.Add(header.Name, header.Value); + } + + return this; + } + /// /// Add URL path to the HTTP client /// @@ -74,11 +136,35 @@ public IHttpTesterClient CreateHttpRequest(Uri baseAddress, bool validateCertifi /// public IHttpTesterClient WithPath(string urlPath) { + if (urlPath == null) + throw new ArgumentException($"{nameof(urlPath)} is null."); + _path = urlPath; return this; } + /// + /// Replace URL path with path parametrs from passed dictionary + /// + /// + /// + public IHttpTesterClient WithPathReplacementValues(Dictionary pathParameters) + { + if (pathParameters == null) + throw new ArgumentException($"{nameof(pathParameters)} is null."); + + if (string.IsNullOrEmpty(_path)) + throw new QAToolKitEngineHttpTesterException("Uri Path is empty. Use 'WithPath' before calling 'WithPathReplacementValues'."); + + foreach (var parameter in pathParameters) + { + _path = _path.Replace($"{{{parameter.Key}}}", parameter.Value); + } + + return this; + } + /// /// Add HTTP headers to the HTTP client /// @@ -86,6 +172,9 @@ public IHttpTesterClient WithPath(string urlPath) /// public IHttpTesterClient WithHeaders(Dictionary headers) { + if (headers == null) + throw new ArgumentException($"{nameof(headers)} is null."); + _headers = headers; return this; @@ -126,6 +215,9 @@ public IHttpTesterClient WithJsonBody(T bodyObject) /// public IHttpTesterClient WithMethod(HttpMethod httpMethod) { + if (httpMethod == null) + throw new ArgumentException($"{nameof(httpMethod)} is null."); + _httpMethod = httpMethod; return this; @@ -138,6 +230,9 @@ public IHttpTesterClient WithMethod(HttpMethod httpMethod) /// public IHttpTesterClient WithQueryParams(Dictionary queryParameters) { + if (queryParameters == null) + throw new ArgumentException($"{nameof(queryParameters)} is null."); + _queryParameters = queryParameters; return this; @@ -151,6 +246,11 @@ public IHttpTesterClient WithQueryParams(Dictionary queryParamet /// public IHttpTesterClient WithBasicAuthentication(string userName, string password) { + if (userName == null) + throw new ArgumentException($"{nameof(userName)} is null."); + if (password == null) + throw new ArgumentException($"{nameof(password)} is null."); + var authenticationString = $"{userName}:{password}"; var base64EncodedAuthenticationString = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(authenticationString)); HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString); @@ -165,6 +265,9 @@ public IHttpTesterClient WithBasicAuthentication(string userName, string passwor /// public IHttpTesterClient WithBearerAuthentication(string accessToken) { + if (accessToken == null) + throw new ArgumentException($"{nameof(accessToken)} is null."); + HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); return this; @@ -255,75 +358,6 @@ public IHttpTesterClient WithMultipart(string httpContentName, string value) return this; } - /// - /// Create a HTTP tester client from QAToolKit HttpRequest object - /// - /// Create tester client with BaseUrl, Path, HttpMethod, Headers and URL Query paramteres read from HttpRequest object. Specify other values and parameters manually. - /// - /// - public IHttpTesterClient CreateHttpRequest(HttpRequest httpRequest, bool validateCertificate = true) - { - if (httpRequest == null) - { - throw new QAToolKitEngineHttpTesterException("'HttpRequest' is null. Pass in the valid object."); - } - - if (HttpClient != null) - { - throw new QAToolKitEngineHttpTesterException("HttpClient is already instantiated. Create new 'HttpTesterClient'."); - } - - var baseAddress = new Uri(httpRequest.BasePath); - - HttpHandler = new HttpClientHandler(); - - if (!validateCertificate && - (baseAddress.Scheme == Uri.UriSchemeHttp || baseAddress.Scheme == Uri.UriSchemeHttps)) - { - HttpHandler.ClientCertificateOptions = ClientCertificateOption.Manual; - HttpHandler.ServerCertificateCustomValidationCallback = - (httpRequestMessage, cert, cetChain, policyErrors) => - { - return true; - }; - } - - HttpClient = new HttpClient(HttpHandler) - { - BaseAddress = baseAddress - }; - - - if (string.IsNullOrEmpty(httpRequest.Path)) - { - throw new QAToolKitEngineHttpTesterException("HttpRequest Path is required."); - } - - _path = httpRequest.Path; - - _httpMethod = httpRequest.Method; - - //Query parameters - if (_queryParameters == null) - _queryParameters = new Dictionary(); - - foreach (var parameter in httpRequest.Parameters.Where(t => t.Location == Location.Query && t.Value != null)) - { - _queryParameters.Add(parameter.Name, parameter.Value); - } - - //Headers - if (_headers == null) - _headers = new Dictionary(); - - foreach (var header in httpRequest.Parameters.Where(t => t.Location == Location.Header && t.Value != null)) - { - _headers.Add(header.Name, header.Value); - } - - return this; - } - /// /// Start the HTTP request /// @@ -331,34 +365,29 @@ public IHttpTesterClient CreateHttpRequest(HttpRequest httpRequest, bool validat public async Task Start() { if (HttpClient == null) - { throw new QAToolKitEngineHttpTesterException("HttpClient is null. Create an object first with 'CreateHttpRequest'."); - } - if (_httpMethod == null) - { throw new QAToolKitEngineHttpTesterException("Define method for a HTTP request."); - } - if (_httpMethod == HttpMethod.Get && _body != null) - { throw new QAToolKitEngineHttpTesterException("'Get' method can not have a HTTP body."); - } - string queryString = ""; + StringBuilder queryString = new StringBuilder(); if (_queryParameters != null) { - queryString = "?"; + queryString.Append("?"); + List array = new List(); foreach (var query in _queryParameters) { - queryString += $"{query.Key}={query.Value}"; + array.Add($"{query.Key}={query.Value}"); } + + queryString.Append(string.Join("&", array)); } var sw = new Stopwatch(); sw.Start(); - using (var requestMessage = new HttpRequestMessage(_httpMethod, _path + queryString)) + using (var requestMessage = new HttpRequestMessage(_httpMethod, _path + queryString.ToString())) { if (_headers != null) { @@ -406,4 +435,4 @@ protected virtual void Dispose(bool disposing) HttpHandler?.Dispose(); } } -} +} \ No newline at end of file diff --git a/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTesterClient.cs b/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTesterClient.cs index f59a0d3..d892500 100644 --- a/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTesterClient.cs +++ b/src/QAToolKit.Engine.HttpTester/Interfaces/IHttpTesterClient.cs @@ -32,6 +32,12 @@ public interface IHttpTesterClient /// IHttpTesterClient WithPath(string urlPath); /// + /// Replace URL path with path parameters from passed dictionary + /// + /// + /// + IHttpTesterClient WithPathReplacementValues(Dictionary pathParameters); + /// /// Add HTTP method to the HTTP client /// ///