diff --git a/HISTORY.md b/HISTORY.md index 2fe856c..031bb62 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,7 @@ +## v5.0.4 +* Ensures all requests have a `User-Agent` string, including `Data` requests. +* Added missing `CancellationToken` to `GetCurrenciesAsync()` + ## v5.0.3 * PR #47: Extra DI interfaces for DI support. Notification event and transaction status constants. Changed `Transaction.Description` return from object to string. Thanks granthoff1107! diff --git a/Source/Coinbase.Tests/ExtensionsForTesting.cs b/Source/Coinbase.Tests/ExtensionsForTesting.cs index 5518034..a6238f6 100644 --- a/Source/Coinbase.Tests/ExtensionsForTesting.cs +++ b/Source/Coinbase.Tests/ExtensionsForTesting.cs @@ -3,6 +3,7 @@ using FluentAssertions; using Flurl.Http.Testing; using Newtonsoft.Json; +using Z.ExtensionMethods; namespace Coinbase.Tests { @@ -29,5 +30,10 @@ public static HttpCallAssertion ShouldHaveRequestBody(this HttpTest test, string test.CallLog.First().RequestBody.Should().Be(json); return new HttpCallAssertion(test.CallLog); } + + public static bool IsAppVeyor(this OperatingSystem os) + { + return Environment.GetEnvironmentVariable("APPVEYOR").IsNotNullOrWhiteSpace(); + } } -} \ No newline at end of file +} diff --git a/Source/Coinbase.Tests/Integration/DataTests.cs b/Source/Coinbase.Tests/Integration/DataTests.cs index dd88484..9d18c60 100644 --- a/Source/Coinbase.Tests/Integration/DataTests.cs +++ b/Source/Coinbase.Tests/Integration/DataTests.cs @@ -4,8 +4,10 @@ using System.Net.Http; using System.Threading.Tasks; using FluentAssertions; +using Flurl.Http; using Flurl.Http.Configuration; using NUnit.Framework; +using Z.ExtensionMethods; namespace Coinbase.Tests.Integration { @@ -13,6 +15,20 @@ public class DataTests { private CoinbaseClient client; + [OneTimeSetUp] + public void BeforeAllTests() + { + if( !Environment.OSVersion.IsAppVeyor() ) + { + var webProxy = new WebProxy("http://localhost.:8888", BypassOnLocal: false); + + FlurlHttp.Configure(settings => + { + settings.HttpClientFactory = new ProxyFactory(webProxy); + }); + } + } + [SetUp] public void BeforeEachTest() { diff --git a/Source/Coinbase/CoinbaseClient.Data.cs b/Source/Coinbase/CoinbaseClient.Data.cs index d86e65d..de3a7fc 100644 --- a/Source/Coinbase/CoinbaseClient.Data.cs +++ b/Source/Coinbase/CoinbaseClient.Data.cs @@ -40,7 +40,7 @@ public interface IDataEndpoint /// /// List known currencies. Currency codes will conform to the ISO 4217 standard where possible. Currencies which have or had no representation in ISO 4217 may use a custom code (e.g. BTC). /// - Task> GetCurrenciesAsync(); + Task> GetCurrenciesAsync(CancellationToken cancellationToken = default); /// /// Get the API server time. @@ -60,6 +60,7 @@ public partial class CoinbaseClient : IDataEndpoint Task> IDataEndpoint.GetBuyPriceAsync(string currencyPair, CancellationToken cancellationToken) { return this.PricesEndpoint + .WithClient(this) .AppendPathSegments(currencyPair, "buy") .GetJsonAsync>(cancellationToken); } @@ -72,6 +73,7 @@ Task> IDataEndpoint.GetBuyPriceAsync(string currencyPair, Cancel Task> IDataEndpoint.GetSellPriceAsync(string currencyPair, CancellationToken cancellationToken) { return this.PricesEndpoint + .WithClient(this) .AppendPathSegments(currencyPair, "sell") .GetJsonAsync>(cancellationToken); } @@ -85,6 +87,7 @@ Task> IDataEndpoint.GetSellPriceAsync(string currencyPair, Cance Task> IDataEndpoint.GetSpotPriceAsync(string currencyPair, DateTime? date, CancellationToken cancellationToken) { var req = this.PricesEndpoint + .WithClient(this) .AppendPathSegments(currencyPair, "spot"); if (!(date is null)) @@ -101,7 +104,8 @@ Task> IDataEndpoint.GetSpotPriceAsync(string currencyPair, DateT /// Base currency (default: USD) Task> IDataEndpoint.GetExchangeRatesAsync(string currency, CancellationToken cancellationToken) { - var req = this.ExchangeRatesEndpoint; + var req = this.ExchangeRatesEndpoint + .WithClient(this); if (!(currency is null)) { @@ -114,9 +118,11 @@ Task> IDataEndpoint.GetExchangeRatesAsync(string currenc /// /// List known currencies. Currency codes will conform to the ISO 4217 standard where possible. Currencies which have or had no representation in ISO 4217 may use a custom code (e.g. BTC). /// - Task> IDataEndpoint.GetCurrenciesAsync() + Task> IDataEndpoint.GetCurrenciesAsync(CancellationToken cancellationToken) { - return this.CurrenciesEndpoint.GetJsonAsync>(); + return this.CurrenciesEndpoint + .WithClient(this) + .GetJsonAsync>(cancellationToken); } @@ -125,7 +131,16 @@ Task> IDataEndpoint.GetCurrenciesAsync() /// Task> IDataEndpoint.GetCurrentTimeAsync(CancellationToken cancellationToken) { - return this.TimeEndpoint.GetJsonAsync>(cancellationToken); + // Manually make this request outside the scope of .WithClient(this) + // because when UseTimeApi =true and when the user makes the first request, + // we need to know the server time but if we use .WithClient(this), + // we'll get stuck in a recursive situation with no base case + // to resolve the actual server time. So, we have to make this + // request out of scope of this configured client. + return this.TimeEndpoint + .WithHeader(HeaderNames.Version, ApiVersionDate) + .WithHeader("User-Agent", UserAgent) + .GetJsonAsync>(cancellationToken); } }