From 864f854ae6fbbe3fefef293135baa575b4805085 Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Tue, 20 Oct 2020 22:10:24 +0200 Subject: [PATCH 1/8] Fixed and improved existing unit tests --- .../Sdk/Api/RequestSender/ApiRequestSender.cs | 16 +- .../Api/RequestSender/HttpRequestSender.cs | 9 +- .../Api/RequestSender/IHttpRequestSender.cs | 4 +- .../Api/RequestSender/ApiRequestSenderTest.cs | 176 ++++++++++++------ .../RequestSender/HttpRequestSenderTest.cs | 25 ++- Bynder/Test/Utils/TestHttpListener.cs | 21 ++- 6 files changed, 177 insertions(+), 74 deletions(-) diff --git a/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs b/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs index 45a1d9f..7a11ea1 100644 --- a/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs @@ -90,13 +90,21 @@ public async Task SendRequestAsync(Requests.Request request) } var httpRequest = CreateHttpRequest(request); - var responseString = await _httpSender.SendHttpRequest(httpRequest).ConfigureAwait(false); - if (!string.IsNullOrEmpty(responseString)) + var response = await _httpSender.SendHttpRequest(httpRequest).ConfigureAwait(false); + + var responseContent = response.Content; + if (response.Content == null) + { + return default(T); + } + + var responseString = await responseContent.ReadAsStringAsync().ConfigureAwait(false); + if (string.IsNullOrEmpty(responseString)) { - return JsonConvert.DeserializeObject(responseString); + return default(T); } - return default(T); + return JsonConvert.DeserializeObject(responseString); } private HttpRequestMessage CreateHttpRequest(Requests.Request request) diff --git a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs index efafd6c..f6d6a34 100644 --- a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs @@ -15,16 +15,15 @@ internal class HttpRequestSender : IHttpRequestSender private readonly HttpClient _httpClient = new HttpClient(); /// - /// Sends the HTTP request and returns the content as string. + /// Sends the HTTP request and returns its response. /// /// The HTTP request response. /// HTTP request. - public async Task SendHttpRequest(HttpRequestMessage httpRequest) + public async Task SendHttpRequest(HttpRequestMessage httpRequest) { - var response = await _httpClient.SendAsync(httpRequest).ConfigureAwait(false); - + HttpResponseMessage response = await _httpClient.SendAsync(httpRequest).ConfigureAwait(false); response.EnsureSuccessStatusCode(); - return await response.Content.ReadAsStringAsync().ConfigureAwait(false); + return response; } /// diff --git a/Bynder/Sdk/Api/RequestSender/IHttpRequestSender.cs b/Bynder/Sdk/Api/RequestSender/IHttpRequestSender.cs index 7b52963..d46f2b4 100644 --- a/Bynder/Sdk/Api/RequestSender/IHttpRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/IHttpRequestSender.cs @@ -14,10 +14,10 @@ namespace Bynder.Sdk.Api.RequestSender internal interface IHttpRequestSender : IDisposable { /// - /// Sends the HTTP request and returns the content as string. + /// Sends the HTTP request and returns its response. /// /// The HTTP request response. /// HTTP request. - Task SendHttpRequest(HttpRequestMessage httpRequest); + Task SendHttpRequest(HttpRequestMessage httpRequest); } } diff --git a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs index 4a8bf95..895ec98 100644 --- a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs @@ -15,23 +15,28 @@ namespace Bynder.Test.Api.RequestSender { public class ApiRequestSenderTest { - [Fact] - public async Task WhenRequestIsPostThenParametersAreAddedToContent() + private const string ACCES_TOKEN = "access_token"; + + private Mock httpSenderMock; + private StubQuery query; + + public ApiRequestSenderTest() { - var httpSenderMock = new Mock(); - var query = new StubQuery + httpSenderMock = new Mock(); + httpSenderMock + .Setup(sender => sender.SendHttpRequest(It.IsAny())) + .Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK))); + + query = new StubQuery { Item1 = "Value" }; - var accessToken = "access_token"; + } - using (ApiRequestSender apiRequestSender = new ApiRequestSender( - new Configuration{ - BaseUrl = new Uri("https://example.bynder.com"), - }, - GetCredentials(true, accessToken), - httpSenderMock.Object - )) + [Fact] + public async Task WhenRequestIsPostThenParametersAreAddedToContent() + { + using (var apiRequestSender = CreateApiRequestSender(true)) { var apiRequest = new ApiRequest() { @@ -43,16 +48,17 @@ public async Task WhenRequestIsPostThenParametersAreAddedToContent() await apiRequestSender.SendRequestAsync(apiRequest); httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.Is( - req => req.RequestUri.PathAndQuery.Contains("/fake/api") + It.Is(req => + req.RequestUri.PathAndQuery.Contains("/fake/api") && req.Method == HttpMethod.Post - && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" + && req.Headers.Authorization.ToString() == $"Bearer {ACCES_TOKEN}" && req.Content.ReadAsStringAsync().Result.Contains("Item1=Value") - ))); + ) + )); httpSenderMock.Verify(sender => sender.SendHttpRequest( It.IsAny() - ), Times.Once); + ), Times.Once); } } @@ -60,21 +66,7 @@ public async Task WhenRequestIsPostThenParametersAreAddedToContent() [Fact] public async Task WhenCredentialInvalidTwoRequestsSent() { - var httpSenderMock = new Mock(); - - var query = new StubQuery - { - Item1 = "Value" - }; - var accessToken = "access_token"; - - using (ApiRequestSender apiRequestSender = new ApiRequestSender( - new Configuration{ - BaseUrl = new Uri("https://example.bynder.com"), - }, - GetCredentials(false, accessToken), - httpSenderMock.Object - )) + using (var apiRequestSender = CreateApiRequestSender(false)) { var apiRequest = new ApiRequest() { @@ -89,15 +81,17 @@ public async Task WhenCredentialInvalidTwoRequestsSent() It.Is( req => req.RequestUri.PathAndQuery.Contains("/oauth2/token") && req.Method == HttpMethod.Post - ))); + ) + )); httpSenderMock.Verify(sender => sender.SendHttpRequest( It.Is( req => req.RequestUri.PathAndQuery.Contains("/fake/api") && req.Method == HttpMethod.Get - && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" + && req.Headers.Authorization.ToString() == $"Bearer {ACCES_TOKEN}" && req.RequestUri.Query.Contains("Item1=Value") - ))); + ) + )); httpSenderMock.Verify(sender => sender.SendHttpRequest( It.IsAny() @@ -108,20 +102,8 @@ public async Task WhenCredentialInvalidTwoRequestsSent() [Fact] public async Task WhenRequestIsGetThenParametersAreAddedToUrl() { - var httpSenderMock = new Mock(); - var query = new StubQuery - { - Item1 = "Value" - }; - var accessToken = "access_token"; - - using (ApiRequestSender apiRequestSender = new ApiRequestSender( - new Configuration{ - BaseUrl = new Uri("https://example.bynder.com"), - }, - GetCredentials(true, accessToken), - httpSenderMock.Object - )) + //await SendRequest(true, HttpMethod.Get) + using (var apiRequestSender = CreateApiRequestSender(true)) { var apiRequest = new ApiRequest { @@ -136,9 +118,10 @@ public async Task WhenRequestIsGetThenParametersAreAddedToUrl() It.Is( req => req.RequestUri.PathAndQuery.Contains("/fake/api") && req.Method == HttpMethod.Get - && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" + && req.Headers.Authorization.ToString() == $"Bearer {ACCES_TOKEN}" && req.RequestUri.Query.Contains("Item1=Value") - ))); + ) + )); httpSenderMock.Verify(sender => sender.SendHttpRequest( It.IsAny() @@ -146,16 +129,103 @@ public async Task WhenRequestIsGetThenParametersAreAddedToUrl() } } - private ICredentials GetCredentials(bool valid = true, string accessToken = null) + //private asynv Task SendRequest( + // bool hasValidCredentials, + // HttpMethod httpMethod + //) + //{ + // var httpSenderMock = new Mock(); + // var query = new StubQuery + // { + // Item1 = "Value" + // }; + // var accessToken = "access_token"; + + // using (ApiRequestSender apiRequestSender = new ApiRequestSender( + // new Configuration + // { + // BaseUrl = new Uri("https://example.bynder.com"), + // }, + // GetCredentials(hasValidCredentials, accessToken), + // httpSenderMock.Object + // )) + // { + // var apiRequest = new ApiRequest + // { + // Path = "/fake/api", + // HTTPMethod = httpMethod, + // Query = query + // }; + + // await apiRequestSender.SendRequestAsync(apiRequest); + + // //httpSenderMock.Verify(sender => sender.SendHttpRequest( + // // It.Is( + // // req => req.RequestUri.PathAndQuery.Contains("/fake/api") + // // && req.Method == httpMethod + // // && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" + // // && req.Content.ReadAsStringAsync().Result.Contains("Item1=Value") + // // ))); + // //httpSenderMock.Verify(sender => sender.SendHttpRequest( + // // It.Is( + // // req => req.RequestUri.PathAndQuery.Contains("/fake/api") + // // && req.Method == HttpMethod.Get + // // && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" + // // && req.RequestUri.Query.Contains("Item1=Value") + // // ))); + // //httpSenderMock.Verify(sender => sender.SendHttpRequest( + // // It.Is( + // // req => req.RequestUri.PathAndQuery.Contains("/fake/api") + // // && req.Method == HttpMethod.Get + // // && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" + // // && req.RequestUri.Query.Contains("Item1=Value") + // // ))); + + + + // ////httpSenderMock.Verify(sender => sender.SendHttpRequest( + // //// It.IsAny() + // ////), Times.Once); + // //httpSenderMock.Verify(sender => sender.SendHttpRequest( + // // It.Is( + // // req => req.RequestUri.PathAndQuery.Contains("/oauth2/token") + // // && req.Method == HttpMethod.Post + // // ) + // //), Times.Once); + + // //httpSenderMock.Verify(sender => sender.SendHttpRequest( + // // It.IsAny() + // //), Times.Exactly(2)); + + // //httpSenderMock.Verify(sender => sender.SendHttpRequest( + // // It.IsAny() + // //), Times.Once); + // } + //} + + private IApiRequestSender CreateApiRequestSender(bool hasValidCredentials) + { + return new ApiRequestSender( + new Configuration + { + BaseUrl = new Uri("https://example.bynder.com"), + }, + GetCredentials(hasValidCredentials), + httpSenderMock.Object + ); + } + + private ICredentials GetCredentials(bool valid) { var credentialsMock = new Mock(); + credentialsMock .Setup(mock => mock.AreValid()) .Returns(valid); credentialsMock .SetupGet(mock => mock.AccessToken) - .Returns(accessToken); + .Returns(ACCES_TOKEN); credentialsMock .SetupGet(mock => mock.TokenType) diff --git a/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs index 82bf28d..b381ed5 100644 --- a/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs @@ -3,6 +3,7 @@ using System.Net; using System.Net.Http; +using System.Threading.Tasks; using Bynder.Sdk.Api.RequestSender; using Bynder.Test.Utils; using Xunit; @@ -12,16 +13,26 @@ namespace Bynder.Test.Api.RequestSender public class HttpRequestSenderTest { [Fact] - public void WhenErrorReceivedAnExceptionIsThown() + public async Task WhenSuccessReceivedResponseIsReturned() { - using (var testHttpListener = new TestHttpListener(HttpStatusCode.Forbidden, null)) + using (var httpListener = new TestHttpListener(HttpStatusCode.OK)) + using (var httpRequestSender = new HttpRequestSender()) { - using (HttpRequestSender apiRequestSender = new HttpRequestSender()) - { - HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, testHttpListener.ListeningUrl); + HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); + var response = await httpRequestSender.SendHttpRequest(requestMessage); - Assert.ThrowsAsync(async () => await apiRequestSender.SendHttpRequest(requestMessage)); - } + } + } + [Fact] + public async Task WhenErrorReceivedAnExceptionIsThown() + { + using (var httpListener = new TestHttpListener(HttpStatusCode.Forbidden)) + using (var httpRequestSender = new HttpRequestSender()) + { + HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); + var doRequest = httpRequestSender.SendHttpRequest(requestMessage); + + await Assert.ThrowsAsync(() => doRequest); } } } diff --git a/Bynder/Test/Utils/TestHttpListener.cs b/Bynder/Test/Utils/TestHttpListener.cs index f1ba166..e389377 100644 --- a/Bynder/Test/Utils/TestHttpListener.cs +++ b/Bynder/Test/Utils/TestHttpListener.cs @@ -20,6 +20,11 @@ public sealed class TestHttpListener : IDisposable /// private readonly HttpListenerFactory _httpListenerFactory; + /// + /// Path of the file which contents will be the response to requests. + /// + private readonly string _responseContent; + /// /// Path of the file which contents will be the response to requests. /// @@ -37,11 +42,13 @@ public sealed class TestHttpListener : IDisposable /// Creates an instance of the class. /// /// HTTP status code that the class will return when having requests + /// String whose contents the class will return in the response /// File whose contents the class will return in the response - public TestHttpListener(HttpStatusCode statusCode, string responsePath) + public TestHttpListener(HttpStatusCode statusCode, string responseContent = null, string responsePath = null) { - _responsePath = responsePath; _statusCode = statusCode; + _responseContent = responseContent; + _responsePath = responsePath; _httpListenerFactory = new HttpListenerFactory(); @@ -97,7 +104,15 @@ private void SendResponse(HttpListenerResponse response) { response.StatusCode = (int)_statusCode; - if (!string.IsNullOrEmpty(_responsePath)) + if (!string.IsNullOrEmpty(_responseContent)) + { + using (var sw = new StreamWriter(response.OutputStream)) + { + sw.Write(_responseContent); + } + } + + else if (!string.IsNullOrEmpty(_responsePath)) { var dr = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); using (var fs = new FileStream(Path.Combine(dr, _responsePath), FileMode.Open, FileAccess.Read)) From 462f5005970af55ee1dae87bb9ad014204b1b6d4 Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Tue, 20 Oct 2020 22:20:46 +0200 Subject: [PATCH 2/8] Add a user agent header every request --- Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs | 7 +++++++ Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs index f6d6a34..91bc9d0 100644 --- a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. using System.Net.Http; +using System.Reflection; using System.Threading.Tasks; namespace Bynder.Sdk.Api.RequestSender @@ -14,6 +15,11 @@ internal class HttpRequestSender : IHttpRequestSender { private readonly HttpClient _httpClient = new HttpClient(); + public string UserAgent + { + get { return "bynder-c-sharp-sdk/" + Assembly.GetExecutingAssembly().GetName().Version.ToString(); } + } + /// /// Sends the HTTP request and returns its response. /// @@ -21,6 +27,7 @@ internal class HttpRequestSender : IHttpRequestSender /// HTTP request. public async Task SendHttpRequest(HttpRequestMessage httpRequest) { + httpRequest.Headers.Add("User-Agent", UserAgent); HttpResponseMessage response = await _httpClient.SendAsync(httpRequest).ConfigureAwait(false); response.EnsureSuccessStatusCode(); return response; diff --git a/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs index b381ed5..3c5f63c 100644 --- a/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Bynder. All rights reserved. // Licensed under the MIT License. See LICENSE file in the project root for full license information. +using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -20,6 +21,10 @@ public async Task WhenSuccessReceivedResponseIsReturned() { HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); var response = await httpRequestSender.SendHttpRequest(requestMessage); + Assert.Equal( + httpRequestSender.UserAgent, + response.RequestMessage.Headers.GetValues("User-Agent").First() + ); } } From 69b114c5cca5c3ca12b97472662a283ab717b1bf Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Tue, 20 Oct 2020 22:31:59 +0200 Subject: [PATCH 3/8] Make the sample a bit more user friendly --- Bynder/Sample/ApiSample.cs | 49 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/Bynder/Sample/ApiSample.cs b/Bynder/Sample/ApiSample.cs index 9b74a90..2e692f2 100644 --- a/Bynder/Sample/ApiSample.cs +++ b/Bynder/Sample/ApiSample.cs @@ -2,10 +2,7 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. using System; -using System.Configuration; -using Bynder.Sdk; using Bynder.Sdk.Service; -using Bynder.Sample; using Bynder.Sample.Utils; using Bynder.Sdk.Query.Asset; using Bynder.Sdk.Query.Collection; @@ -24,6 +21,13 @@ public class ApiSample /// /// arguments to main public static void Main(string[] args) + { + //Choose your authentication method by commenting one of these lines. + PermanentToken(); + Oauth(); + } + + private static void PermanentToken() { using (var client = ClientFactory.Create(Configuration.FromJson("Config.json"))) { @@ -41,34 +45,33 @@ public static void Main(string[] args) Console.WriteLine(collection.Name); } } + } + private static void Oauth() + { using (var waitForToken = new WaitForToken()) + using (var listener = new UrlHttpListener("http://localhost:8888/", waitForToken)) + using (var client = ClientFactory.Create(Configuration.FromJson("Config.json"))) { - using (var listener = new UrlHttpListener("http://localhost:8888/", waitForToken)) - { - using (var client = ClientFactory.Create(Configuration.FromJson("Config.json"))) - { - Browser.Launch(client.GetOAuthService().GetAuthorisationUrl("state example", "offline asset:read collection:read")); - waitForToken.WaitHandle.WaitOne(50000); + Browser.Launch(client.GetOAuthService().GetAuthorisationUrl("state example", "offline asset:read collection:read")); + waitForToken.WaitHandle.WaitOne(50000); - if (waitForToken.Success) - { - client.GetOAuthService().GetAccessTokenAsync(waitForToken.Token, "offline asset:read collection:read").Wait(); + if (waitForToken.Success) + { + client.GetOAuthService().GetAccessTokenAsync(waitForToken.Token, "offline asset:read collection:read").Wait(); - var mediaList = client.GetAssetService().GetMediaListAsync(new MediaQuery()).Result; + var mediaList = client.GetAssetService().GetMediaListAsync(new MediaQuery()).Result; - foreach (var media in mediaList) - { - Console.WriteLine(media.Name); - } + foreach (var media in mediaList) + { + Console.WriteLine(media.Name); + } - var collectionList = client.GetCollectionService().GetCollectionsAsync(new GetCollectionsQuery()).Result; + var collectionList = client.GetCollectionService().GetCollectionsAsync(new GetCollectionsQuery()).Result; - foreach (var collection in collectionList) - { - Console.WriteLine(collection.Name); - } - } + foreach (var collection in collectionList) + { + Console.WriteLine(collection.Name); } } } From a5e85173e9732dccbbacda93a1950be00fe58d9e Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Tue, 20 Oct 2020 22:39:14 +0200 Subject: [PATCH 4/8] Some missing stuff --- .../Sdk/Api/RequestSender/ApiRequestSender.cs | 1 - .../Api/RequestSender/HttpRequestSender.cs | 5 +- .../Api/RequestSender/ApiRequestSenderTest.cs | 75 ------------------- .../RequestSender/HttpRequestSenderTest.cs | 5 +- 4 files changed, 7 insertions(+), 79 deletions(-) diff --git a/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs b/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs index 7a11ea1..a1774e8 100644 --- a/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs @@ -9,7 +9,6 @@ using System.Threading.Tasks; using Bynder.Sdk.Model; using Bynder.Sdk.Api.Requests; -using Bynder.Sdk.Service; using Newtonsoft.Json; using Bynder.Sdk.Query.Decoder; using Bynder.Sdk.Query; diff --git a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs index 91bc9d0..2794f8d 100644 --- a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs @@ -15,6 +15,9 @@ internal class HttpRequestSender : IHttpRequestSender { private readonly HttpClient _httpClient = new HttpClient(); + /// + /// User-Agent header we add to each request. + /// public string UserAgent { get { return "bynder-c-sharp-sdk/" + Assembly.GetExecutingAssembly().GetName().Version.ToString(); } @@ -28,7 +31,7 @@ public string UserAgent public async Task SendHttpRequest(HttpRequestMessage httpRequest) { httpRequest.Headers.Add("User-Agent", UserAgent); - HttpResponseMessage response = await _httpClient.SendAsync(httpRequest).ConfigureAwait(false); + var response = await _httpClient.SendAsync(httpRequest).ConfigureAwait(false); response.EnsureSuccessStatusCode(); return response; } diff --git a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs index 895ec98..6d36151 100644 --- a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs @@ -102,7 +102,6 @@ public async Task WhenCredentialInvalidTwoRequestsSent() [Fact] public async Task WhenRequestIsGetThenParametersAreAddedToUrl() { - //await SendRequest(true, HttpMethod.Get) using (var apiRequestSender = CreateApiRequestSender(true)) { var apiRequest = new ApiRequest @@ -129,80 +128,6 @@ public async Task WhenRequestIsGetThenParametersAreAddedToUrl() } } - //private asynv Task SendRequest( - // bool hasValidCredentials, - // HttpMethod httpMethod - //) - //{ - // var httpSenderMock = new Mock(); - // var query = new StubQuery - // { - // Item1 = "Value" - // }; - // var accessToken = "access_token"; - - // using (ApiRequestSender apiRequestSender = new ApiRequestSender( - // new Configuration - // { - // BaseUrl = new Uri("https://example.bynder.com"), - // }, - // GetCredentials(hasValidCredentials, accessToken), - // httpSenderMock.Object - // )) - // { - // var apiRequest = new ApiRequest - // { - // Path = "/fake/api", - // HTTPMethod = httpMethod, - // Query = query - // }; - - // await apiRequestSender.SendRequestAsync(apiRequest); - - // //httpSenderMock.Verify(sender => sender.SendHttpRequest( - // // It.Is( - // // req => req.RequestUri.PathAndQuery.Contains("/fake/api") - // // && req.Method == httpMethod - // // && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" - // // && req.Content.ReadAsStringAsync().Result.Contains("Item1=Value") - // // ))); - // //httpSenderMock.Verify(sender => sender.SendHttpRequest( - // // It.Is( - // // req => req.RequestUri.PathAndQuery.Contains("/fake/api") - // // && req.Method == HttpMethod.Get - // // && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" - // // && req.RequestUri.Query.Contains("Item1=Value") - // // ))); - // //httpSenderMock.Verify(sender => sender.SendHttpRequest( - // // It.Is( - // // req => req.RequestUri.PathAndQuery.Contains("/fake/api") - // // && req.Method == HttpMethod.Get - // // && req.Headers.Authorization.ToString() == $"Bearer {accessToken}" - // // && req.RequestUri.Query.Contains("Item1=Value") - // // ))); - - - - // ////httpSenderMock.Verify(sender => sender.SendHttpRequest( - // //// It.IsAny() - // ////), Times.Once); - // //httpSenderMock.Verify(sender => sender.SendHttpRequest( - // // It.Is( - // // req => req.RequestUri.PathAndQuery.Contains("/oauth2/token") - // // && req.Method == HttpMethod.Post - // // ) - // //), Times.Once); - - // //httpSenderMock.Verify(sender => sender.SendHttpRequest( - // // It.IsAny() - // //), Times.Exactly(2)); - - // //httpSenderMock.Verify(sender => sender.SendHttpRequest( - // // It.IsAny() - // //), Times.Once); - // } - //} - private IApiRequestSender CreateApiRequestSender(bool hasValidCredentials) { return new ApiRequestSender( diff --git a/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs index 3c5f63c..4d6c679 100644 --- a/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/HttpRequestSenderTest.cs @@ -19,8 +19,9 @@ public async Task WhenSuccessReceivedResponseIsReturned() using (var httpListener = new TestHttpListener(HttpStatusCode.OK)) using (var httpRequestSender = new HttpRequestSender()) { - HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); + var requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); var response = await httpRequestSender.SendHttpRequest(requestMessage); + Assert.Equal( httpRequestSender.UserAgent, response.RequestMessage.Headers.GetValues("User-Agent").First() @@ -34,7 +35,7 @@ public async Task WhenErrorReceivedAnExceptionIsThown() using (var httpListener = new TestHttpListener(HttpStatusCode.Forbidden)) using (var httpRequestSender = new HttpRequestSender()) { - HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); + var requestMessage = new HttpRequestMessage(HttpMethod.Get, httpListener.ListeningUrl); var doRequest = httpRequestSender.SendHttpRequest(requestMessage); await Assert.ThrowsAsync(() => doRequest); From e4584ff9a6748d202b31960c69eff4eec0465380 Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Wed, 21 Oct 2020 15:59:14 +0200 Subject: [PATCH 5/8] Added metadata to project / version bump --- Bynder/Sdk/Bynder.Sdk.csproj | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Bynder/Sdk/Bynder.Sdk.csproj b/Bynder/Sdk/Bynder.Sdk.csproj index c4688c3..ac17e6e 100644 --- a/Bynder/Sdk/Bynder.Sdk.csproj +++ b/Bynder/Sdk/Bynder.Sdk.csproj @@ -6,10 +6,29 @@ Bynder Bynder.Sdk Copyright © Bynder + true + 2.2.0 + BynderDevops + The main goal of this SDK is to speed up the integration of Bynder customers who use C# making it easier to connect to the Bynder API (http://docs.bynder.apiary.io/) and executing requests on it. + https://bynder.com/static/3.0/img/favicon-black.ico + en + https://github.com/Bynder/bynder-c-sharp-sdk/blob/master/LICENSE + true + BynderDevops + https://github.com/Bynder/bynder-c-sharp-sdk + Adds the SDK's name and version to each request in the User-Agent header, to enable better insight in the Bynder API usage. + The main goal of this SDK is to speed up the integration of Bynder customers who use C# making it easier to connect to the Bynder API (http://docs.bynder.apiary.io/) and executing requests on it. + Bynder API C# SDK + Bynder.Sdk + Bynder.Sdk + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + From 116ee60d936da0c090296489f8dc65a88c9bca41 Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Wed, 21 Oct 2020 15:59:33 +0200 Subject: [PATCH 6/8] Added common apple stuff to gitignore --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 55423de..0250353 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ +# General macOS +.DS_Store +.AppleDouble +.LSOverride + # Build results bin/ obj/ From 14914c1f82a53286446ed284286c64efbcd92b7f Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Wed, 21 Oct 2020 16:54:06 +0200 Subject: [PATCH 7/8] Use conventional style for constants in C# --- Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs index 6d36151..d10ce27 100644 --- a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs @@ -15,7 +15,7 @@ namespace Bynder.Test.Api.RequestSender { public class ApiRequestSenderTest { - private const string ACCES_TOKEN = "access_token"; + private const string AccessToken = "access_token"; private Mock httpSenderMock; private StubQuery query; @@ -51,7 +51,7 @@ public async Task WhenRequestIsPostThenParametersAreAddedToContent() It.Is(req => req.RequestUri.PathAndQuery.Contains("/fake/api") && req.Method == HttpMethod.Post - && req.Headers.Authorization.ToString() == $"Bearer {ACCES_TOKEN}" + && req.Headers.Authorization.ToString() == $"Bearer {AccessToken}" && req.Content.ReadAsStringAsync().Result.Contains("Item1=Value") ) )); @@ -88,7 +88,7 @@ public async Task WhenCredentialInvalidTwoRequestsSent() It.Is( req => req.RequestUri.PathAndQuery.Contains("/fake/api") && req.Method == HttpMethod.Get - && req.Headers.Authorization.ToString() == $"Bearer {ACCES_TOKEN}" + && req.Headers.Authorization.ToString() == $"Bearer {AccessToken}" && req.RequestUri.Query.Contains("Item1=Value") ) )); @@ -117,7 +117,7 @@ public async Task WhenRequestIsGetThenParametersAreAddedToUrl() It.Is( req => req.RequestUri.PathAndQuery.Contains("/fake/api") && req.Method == HttpMethod.Get - && req.Headers.Authorization.ToString() == $"Bearer {ACCES_TOKEN}" + && req.Headers.Authorization.ToString() == $"Bearer {AccessToken}" && req.RequestUri.Query.Contains("Item1=Value") ) )); @@ -150,7 +150,7 @@ private ICredentials GetCredentials(bool valid) credentialsMock .SetupGet(mock => mock.AccessToken) - .Returns(ACCES_TOKEN); + .Returns(AccessToken); credentialsMock .SetupGet(mock => mock.TokenType) From 44c7733f72aaf661ff3bf1605c56ff5df4dc6266 Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Wed, 21 Oct 2020 18:05:08 +0200 Subject: [PATCH 8/8] Moved string literals to constants --- .../Sdk/Api/RequestSender/ApiRequestSender.cs | 4 +- .../Api/RequestSender/HttpRequestSender.cs | 2 +- .../Api/RequestSender/ApiRequestSenderTest.cs | 165 ++++++++---------- 3 files changed, 79 insertions(+), 92 deletions(-) diff --git a/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs b/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs index a1774e8..e32903e 100644 --- a/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/ApiRequestSender.cs @@ -27,6 +27,8 @@ internal class ApiRequestSender : IApiRequestSender private SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); private IHttpRequestSender _httpSender; + public const string TokenPath = "/v6/authentication/oauth2/token"; + /// /// Initializes a new instance of the class. /// @@ -138,7 +140,7 @@ private async Task RefreshToken() { Authenticated = false, Query = query, - Path = $"/v6/authentication/oauth2/token", + Path = TokenPath, HTTPMethod = HttpMethod.Post }; diff --git a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs index 2794f8d..3de9ecf 100644 --- a/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs +++ b/Bynder/Sdk/Api/RequestSender/HttpRequestSender.cs @@ -20,7 +20,7 @@ internal class HttpRequestSender : IHttpRequestSender /// public string UserAgent { - get { return "bynder-c-sharp-sdk/" + Assembly.GetExecutingAssembly().GetName().Version.ToString(); } + get { return $"bynder-c-sharp-sdk/{Assembly.GetExecutingAssembly().GetName().Version.ToString()}"; } } /// diff --git a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs index d10ce27..8d98bdc 100644 --- a/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs +++ b/Bynder/Test/Api/RequestSender/ApiRequestSenderTest.cs @@ -15,117 +15,102 @@ namespace Bynder.Test.Api.RequestSender { public class ApiRequestSenderTest { - private const string AccessToken = "access_token"; + private const string _accessToken = "some_access_token"; + private const string _authHeader = "Bearer " + _accessToken; + private const string _path = "/fake/api"; + private const string _queryValue = "some_query_value"; + private const string _queryString = "Item1=" + _queryValue; - private Mock httpSenderMock; - private StubQuery query; + private Mock _httpSenderMock; + private StubQuery _query; public ApiRequestSenderTest() { - httpSenderMock = new Mock(); - httpSenderMock + _httpSenderMock = new Mock(); + _httpSenderMock .Setup(sender => sender.SendHttpRequest(It.IsAny())) .Returns(Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK))); - - query = new StubQuery + _query = new StubQuery { - Item1 = "Value" + Item1 = _queryValue }; } [Fact] public async Task WhenRequestIsPostThenParametersAreAddedToContent() { - using (var apiRequestSender = CreateApiRequestSender(true)) - { - var apiRequest = new ApiRequest() - { - Path = "/fake/api", - HTTPMethod = HttpMethod.Post, - Query = query - }; - - await apiRequestSender.SendRequestAsync(apiRequest); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.Is(req => - req.RequestUri.PathAndQuery.Contains("/fake/api") - && req.Method == HttpMethod.Post - && req.Headers.Authorization.ToString() == $"Bearer {AccessToken}" - && req.Content.ReadAsStringAsync().Result.Contains("Item1=Value") - ) - )); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.IsAny() - ), Times.Once); - } + await SendRequest(hasValidCredentials: true, httpMethod: HttpMethod.Post); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.Is(req => + req.RequestUri.PathAndQuery.Contains(_path) + && req.Method == HttpMethod.Post + && req.Headers.Authorization.ToString() == _authHeader + && req.Content.ReadAsStringAsync().Result.Contains(_queryString) + ) + )); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.IsAny() + ), Times.Once); } [Fact] public async Task WhenCredentialInvalidTwoRequestsSent() { - using (var apiRequestSender = CreateApiRequestSender(false)) - { - var apiRequest = new ApiRequest() - { - Path = "/fake/api", - HTTPMethod = HttpMethod.Get, - Query = query - }; - - await apiRequestSender.SendRequestAsync(apiRequest); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.Is( - req => req.RequestUri.PathAndQuery.Contains("/oauth2/token") - && req.Method == HttpMethod.Post - ) - )); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.Is( - req => req.RequestUri.PathAndQuery.Contains("/fake/api") - && req.Method == HttpMethod.Get - && req.Headers.Authorization.ToString() == $"Bearer {AccessToken}" - && req.RequestUri.Query.Contains("Item1=Value") - ) - )); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.IsAny() - ), Times.Exactly(2)); - } + await SendRequest(hasValidCredentials: false, httpMethod: HttpMethod.Get); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.Is( + req => req.RequestUri.PathAndQuery == ApiRequestSender.TokenPath + && req.Method == HttpMethod.Post + ) + )); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.Is( + req => req.RequestUri.PathAndQuery.Contains(_path) + && req.Method == HttpMethod.Get + && req.Headers.Authorization.ToString() == _authHeader + && req.RequestUri.Query.Contains(_queryString) + ) + )); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.IsAny() + ), Times.Exactly(2)); } [Fact] public async Task WhenRequestIsGetThenParametersAreAddedToUrl() { - using (var apiRequestSender = CreateApiRequestSender(true)) - { - var apiRequest = new ApiRequest + await SendRequest(hasValidCredentials: true, httpMethod: HttpMethod.Get); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.Is( + req => req.RequestUri.PathAndQuery.Contains(_path) + && req.Method == HttpMethod.Get + && req.Headers.Authorization.ToString() == _authHeader + && req.RequestUri.Query.Contains(_queryString) + ) + )); + + _httpSenderMock.Verify(sender => sender.SendHttpRequest( + It.IsAny() + ), Times.Once); + } + + private async Task SendRequest(bool hasValidCredentials, HttpMethod httpMethod) + { + await CreateApiRequestSender(hasValidCredentials).SendRequestAsync( + new ApiRequest() { - Path = "/fake/api", - HTTPMethod = HttpMethod.Get, - Query = query - }; - - await apiRequestSender.SendRequestAsync(apiRequest); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.Is( - req => req.RequestUri.PathAndQuery.Contains("/fake/api") - && req.Method == HttpMethod.Get - && req.Headers.Authorization.ToString() == $"Bearer {AccessToken}" - && req.RequestUri.Query.Contains("Item1=Value") - ) - )); - - httpSenderMock.Verify(sender => sender.SendHttpRequest( - It.IsAny() - ), Times.Once); - } + Path = _path, + HTTPMethod = httpMethod, + Query = _query + } + ); } private IApiRequestSender CreateApiRequestSender(bool hasValidCredentials) @@ -136,21 +121,21 @@ private IApiRequestSender CreateApiRequestSender(bool hasValidCredentials) BaseUrl = new Uri("https://example.bynder.com"), }, GetCredentials(hasValidCredentials), - httpSenderMock.Object + _httpSenderMock.Object ); } - private ICredentials GetCredentials(bool valid) + private ICredentials GetCredentials(bool isValid) { var credentialsMock = new Mock(); credentialsMock .Setup(mock => mock.AreValid()) - .Returns(valid); + .Returns(isValid); credentialsMock .SetupGet(mock => mock.AccessToken) - .Returns(AccessToken); + .Returns(_accessToken); credentialsMock .SetupGet(mock => mock.TokenType)