mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-17 03:12:56 +00:00
CryptoExchange V12 (#281)
* Result types: * (Web)CallResult types are replaced by HttpResult, WebSocketResult and QueryResult with the same logic * Updated result types to record type * Result creation can be done with (Http/WebSocket/Query)Result.Ok(..) and .Fail(..) * Removed implicit result type conversion to bool, `if (result)` no longer works, instead use `if (result.Success)` * Replaced CallResult.SuccessResult with CallResult.Ok() * Fixed result object nullability hinting, for example Data might be null if Success isn't checked for true * Parameters & serialization: * Added support for `enabled` and `disabled` strings to bool converter * Removed ParameterCollection type, has been replaced by Parameters type * Removed ArraySerialization, OrderParameters and ParameterOrderComparer properties from RestApiClient, moved to ParameterSerializationsSettings * Updated RestRequestConfiguration in AuthenticationProvider.ProcessRequest to contain the full RequestDefinition instead of copied fields * Clients: * Updated Api client constructor logging parameter from ILogger to ILoggerFactory? * Added Api client constructor exchange name parameter * Added ToString overrides on base API types * Added Exchange property on BaseApiClient * Added ApiCredentials property on IRestApiClient and ISocketApiClient interfaces * Updated ILogger source from client name to topic specific client name * Removed logging from client creation * Fixed BaseRestClient SetApiCredentials not marked as virtual * Rest: * Added BaseAddress to RequestDefinition object * Updated RestApiClient AuthenticationProvider logic from private to protected and virtual * Removed RestApiClient.SendAsync baseAddress parameter removed * Removed RestApiClient.SendAsync without type parameter * WebSocket: * Updated MessageRouting definition into CreateForEvent for subscriptions and CreateForQuery for queries * Improved Query type safety with CeateForQuery which allows second parameter for specifying the result type * Renamed MessageRouter.CreateWithoutHandler to CreateVoid * Updated SocketApiClient.GetSocketConnection to check connection uri instead of Tag for finding compatible connections * Removed unused UnhandledMessageExpected property SocketApiClient * Fixed issue in SocketApiClient.GetSocketConnection causing requests to always wait the full max 10 seconds when there was a reconnecting socket * Shared APIs: * Updated Option definitions to always require the exchange name as first parameter * Added missing dedicated option types * Added Discover method on ISharedClient interface, returning info on supported capabilities and operations * Added SharedRequest GetParamValue helper method accepting multiple parameter names * Added ResetStaticExchangeParameters method on ExchangeParameters * Added Status property to SharedWithdrawal model * Added TradingModes property to SharedBalance model * Updated ExchangeSymbolCache to support multiple environments and additional key separation * Updated Shared ExchangeParameters parameter names to be case insensitive * Updated code comments * Replaced ExchangeResult with ExchangeCallResult type * Removed AsExchangeResult/ExchangeWebResult * Removed TradingMode from the response model, only maintained on models where it makes sense * Removed IListenKey support, listen keys now rely on internal management with TokenManager * Rate limiting: * Fixed websocket connection attempts counting towards rate limit even when server could not be reached * Removed host from rate limit methods, now part of the already provided RequestDefinition * Added amount parameter to RateLimit Reset method to allow partially resetting the limit * Added TokenManager implementation for automatic listenkey/token management * Added UserClientProvider base class * Added async streaming on UserDataTracker items with StreamUpdatesAsync * Added cancellation token support to UserDataTracker starting * Added Unit type for non-result types * Added ServerError constructor taking ErrorType and message to make it easier to create * Added SupportedEnvironments property to PlatformInfo * Updated SymbolOrderBook DoResyncAsync to return CallResult instead of CallResult<bool> which was redundant * Various small performance improvements
This commit is contained in:
@@ -14,157 +14,41 @@ namespace CryptoExchange.Net.UnitTests
|
||||
[Test]
|
||||
public void TestBasicErrorCallResult()
|
||||
{
|
||||
var result = new CallResult(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
var result = CallResult.Fail(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
|
||||
ClassicAssert.AreSame(result.Error!.ErrorCode, "TestError");
|
||||
ClassicAssert.IsFalse(result);
|
||||
ClassicAssert.IsFalse(result.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBasicSuccessCallResult()
|
||||
{
|
||||
var result = new CallResult(null);
|
||||
var result = CallResult.Ok();
|
||||
|
||||
ClassicAssert.IsNull(result.Error);
|
||||
Assert.That(result);
|
||||
Assert.That(result.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCallResultError()
|
||||
{
|
||||
var result = new CallResult<object>(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
var result = CallResult.Fail<object>(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
|
||||
ClassicAssert.AreSame(result.Error!.ErrorCode, "TestError");
|
||||
ClassicAssert.IsNull(result.Data);
|
||||
ClassicAssert.IsFalse(result);
|
||||
ClassicAssert.IsFalse(result.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCallResultSuccess()
|
||||
{
|
||||
var result = new CallResult<object>(new object());
|
||||
var result = CallResult.Ok<object>(new object());
|
||||
|
||||
ClassicAssert.IsNull(result.Error);
|
||||
ClassicAssert.IsNotNull(result.Data);
|
||||
Assert.That(result);
|
||||
Assert.That(result.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCallResultSuccessAs()
|
||||
{
|
||||
var result = new CallResult<TestObjectResult>(new TestObjectResult());
|
||||
var asResult = result.As<TestObject2>(result.Data.InnerData);
|
||||
|
||||
ClassicAssert.IsNull(asResult.Error);
|
||||
ClassicAssert.IsNotNull(asResult.Data);
|
||||
Assert.That(asResult.Data is not null);
|
||||
Assert.That(asResult);
|
||||
Assert.That(asResult.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCallResultErrorAs()
|
||||
{
|
||||
var result = new CallResult<TestObjectResult>(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
var asResult = result.As<TestObject2>(default);
|
||||
|
||||
ClassicAssert.IsNotNull(asResult.Error);
|
||||
ClassicAssert.AreSame(asResult.Error!.ErrorCode, "TestError");
|
||||
ClassicAssert.IsNull(asResult.Data);
|
||||
ClassicAssert.IsFalse(asResult);
|
||||
ClassicAssert.IsFalse(asResult.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCallResultErrorAsError()
|
||||
{
|
||||
var result = new CallResult<TestObjectResult>(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown));
|
||||
|
||||
ClassicAssert.IsNotNull(asResult.Error);
|
||||
ClassicAssert.AreSame(asResult.Error!.ErrorCode, "TestError2");
|
||||
ClassicAssert.IsNull(asResult.Data);
|
||||
ClassicAssert.IsFalse(asResult);
|
||||
ClassicAssert.IsFalse(asResult.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWebCallResultErrorAsError()
|
||||
{
|
||||
var result = new WebCallResult<TestObjectResult>(new ServerError("TestError", ErrorInfo.Unknown));
|
||||
var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown));
|
||||
|
||||
ClassicAssert.IsNotNull(asResult.Error);
|
||||
ClassicAssert.AreSame(asResult.Error!.ErrorCode, "TestError2");
|
||||
ClassicAssert.IsNull(asResult.Data);
|
||||
ClassicAssert.IsFalse(asResult);
|
||||
ClassicAssert.IsFalse(asResult.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWebCallResultSuccessAsError()
|
||||
{
|
||||
var result = new WebCallResult<TestObjectResult>(
|
||||
System.Net.HttpStatusCode.OK,
|
||||
HttpVersion.Version11,
|
||||
new HttpResponseMessage().Headers,
|
||||
TimeSpan.FromSeconds(1),
|
||||
null,
|
||||
"{}",
|
||||
1,
|
||||
"https://test.com/api",
|
||||
null,
|
||||
HttpMethod.Get,
|
||||
new HttpRequestMessage().Headers,
|
||||
ResultDataSource.Server,
|
||||
new TestObjectResult(),
|
||||
null);
|
||||
var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown));
|
||||
|
||||
ClassicAssert.IsNotNull(asResult.Error);
|
||||
Assert.That(asResult.Error!.ErrorCode == "TestError2");
|
||||
Assert.That(asResult.ResponseStatusCode == System.Net.HttpStatusCode.OK);
|
||||
Assert.That(asResult.ResponseTime == TimeSpan.FromSeconds(1));
|
||||
Assert.That(asResult.RequestUrl == "https://test.com/api");
|
||||
Assert.That(asResult.RequestMethod == HttpMethod.Get);
|
||||
ClassicAssert.IsNull(asResult.Data);
|
||||
ClassicAssert.IsFalse(asResult);
|
||||
ClassicAssert.IsFalse(asResult.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWebCallResultSuccessAsSuccess()
|
||||
{
|
||||
var result = new WebCallResult<TestObjectResult>(
|
||||
System.Net.HttpStatusCode.OK,
|
||||
HttpVersion.Version11,
|
||||
new HttpResponseMessage().Headers,
|
||||
TimeSpan.FromSeconds(1),
|
||||
null,
|
||||
"{}",
|
||||
1,
|
||||
"https://test.com/api",
|
||||
null,
|
||||
HttpMethod.Get,
|
||||
new HttpRequestMessage().Headers,
|
||||
ResultDataSource.Server,
|
||||
new TestObjectResult(),
|
||||
null);
|
||||
var asResult = result.As<TestObject2>(result.Data.InnerData);
|
||||
|
||||
ClassicAssert.IsNull(asResult.Error);
|
||||
Assert.That(asResult.ResponseStatusCode == System.Net.HttpStatusCode.OK);
|
||||
Assert.That(asResult.ResponseTime == TimeSpan.FromSeconds(1));
|
||||
Assert.That(asResult.RequestUrl == "https://test.com/api");
|
||||
Assert.That(asResult.RequestMethod == HttpMethod.Get);
|
||||
ClassicAssert.IsNotNull(asResult.Data);
|
||||
Assert.That(asResult);
|
||||
Assert.That(asResult.Success);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestObjectResult
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
|
||||
client.ApiClient1.SetParameterPosition(httpMethod, pos);
|
||||
client.ApiClient1.SetNextResponse("{}", System.Net.HttpStatusCode.OK);
|
||||
|
||||
var result = await client.ApiClient1.GetResponseAsync<TestObject>(httpMethod, new ParameterCollection
|
||||
var result = await client.ApiClient1.GetResponseAsync<TestObject>(httpMethod, new Parameters(new ParameterSerializationSettings())
|
||||
{
|
||||
{ "TestParam1", "Value1" },
|
||||
{ "TestParam2", 2 },
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
|
||||
var result = await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => {}, false, default);
|
||||
|
||||
// act
|
||||
await client.UnsubscribeAsync(result.Data);
|
||||
await client.UnsubscribeAsync(result.Data!);
|
||||
|
||||
// assert
|
||||
Assert.That(socket.Connected == false);
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var symbols = CreateTestSymbols();
|
||||
|
||||
// act
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
var hasCached = ExchangeSymbolCache.HasCached(topicId);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
var hasCached = ExchangeSymbolCache.HasCached(topicId, "Env", null);
|
||||
|
||||
// assert
|
||||
Assert.That(hasCached, Is.True);
|
||||
@@ -52,14 +52,14 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var symbols = CreateTestSymbols();
|
||||
|
||||
// act
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// assert
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "BTCUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "ETHUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "BTCEUR"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "ETHBTC"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "XRPUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "BTCUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "ETHUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "BTCEUR"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "ETHBTC"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "XRPUSDT"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -78,13 +78,13 @@ namespace CryptoExchange.Net.UnitTests
|
||||
};
|
||||
|
||||
// act
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, initialSymbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, updatedSymbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, initialSymbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, updatedSymbols);
|
||||
|
||||
// assert - should still have only the initial symbol since less than 60 minutes passed
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "BTCUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "BTCUSDT"), Is.True);
|
||||
// The second update should not have been applied
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "ETHUSDT"), Is.False);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "ETHUSDT"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -95,8 +95,8 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var symbols = Array.Empty<SharedSpotSymbol>();
|
||||
|
||||
// act
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
var hasCached = ExchangeSymbolCache.HasCached(topicId);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
var hasCached = ExchangeSymbolCache.HasCached(topicId, "Env", null);
|
||||
|
||||
// assert
|
||||
Assert.That(hasCached, Is.False);
|
||||
@@ -109,7 +109,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.HasCached(nonExistentTopic);
|
||||
var result = ExchangeSymbolCache.HasCached(nonExistentTopic, "Env", null);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -121,10 +121,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeWithData";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.HasCached(topicId);
|
||||
var result = ExchangeSymbolCache.HasCached(topicId, "Env", null);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.True);
|
||||
@@ -135,10 +135,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
// arrange
|
||||
var topicId = "ExchangeNoData";
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, Array.Empty<SharedSpotSymbol>());
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, Array.Empty<SharedSpotSymbol>());
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.HasCached(topicId);
|
||||
var result = ExchangeSymbolCache.HasCached(topicId, "Env", null);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -150,10 +150,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeSupports";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "BTCUSDT");
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.True);
|
||||
@@ -165,10 +165,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeNoSupport";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "LINKUSDT");
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, "LINKUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -181,7 +181,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(nonExistentTopic, "BTCUSDT");
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(nonExistentTopic, "Env", null, "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -193,11 +193,11 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeSharedSymbol";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
var sharedSymbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, sharedSymbol);
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, sharedSymbol);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.True);
|
||||
@@ -209,11 +209,11 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeNoSharedSymbol";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
var sharedSymbol = new SharedSymbol(TradingMode.Spot, "LINK", "USDT");
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, sharedSymbol);
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, sharedSymbol);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -225,11 +225,11 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeDifferentMode";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
var sharedSymbol = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, sharedSymbol);
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, sharedSymbol);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -243,7 +243,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var sharedSymbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(nonExistentTopic, sharedSymbol);
|
||||
var result = ExchangeSymbolCache.SupportsSymbol(nonExistentTopic, "Env", null, sharedSymbol);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.False);
|
||||
@@ -255,10 +255,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeBaseAsset";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "BTC");
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Env", null, "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
@@ -273,10 +273,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeCaseInsensitive";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "btc");
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Env", null, "btc");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
@@ -289,10 +289,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeNoBaseAsset";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "LINK");
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Env", null, "LINK");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
@@ -306,7 +306,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(nonExistentTopic, "BTC");
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(nonExistentTopic, "Env", null, "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
@@ -319,10 +319,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeParse";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "BTCUSDT");
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "Env", null, "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
@@ -338,10 +338,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeNoParse";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "LINKUSDT");
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "Env", null, "LINKUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Null);
|
||||
@@ -353,10 +353,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
// arrange
|
||||
var topicId = "ExchangeNullSymbol";
|
||||
var symbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, null);
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "Env", null, null);
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Null);
|
||||
@@ -369,7 +369,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(nonExistentTopic, "BTCUSDT");
|
||||
var result = ExchangeSymbolCache.ParseSymbol(nonExistentTopic, "Env", null, "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Null);
|
||||
@@ -391,14 +391,14 @@ namespace CryptoExchange.Net.UnitTests
|
||||
};
|
||||
|
||||
// act
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topic1, symbols1);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topic2, symbols2);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topic1, "Env", null, symbols1);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topic2, "Env", null, symbols2);
|
||||
|
||||
// assert
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic1, "BTCUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic1, "ETHUSDT"), Is.False);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic2, "ETHUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic2, "BTCUSDT"), Is.False);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic1, "Env", null, "BTCUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic1, "Env", null, "ETHUSDT"), Is.False);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic2, "Env", null, "ETHUSDT"), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic2, "Env", null, "BTCUSDT"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -411,14 +411,14 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var allSymbols = spotSymbols.Concat(futuresSymbols).ToArray();
|
||||
|
||||
// act
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, allSymbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, allSymbols);
|
||||
|
||||
// assert
|
||||
var spotSymbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
var futuresSymbol = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
|
||||
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, spotSymbol), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, futuresSymbol), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, spotSymbol), Is.True);
|
||||
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "Env", null, futuresSymbol), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -429,10 +429,10 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
var futuresSymbols = CreateFuturesSymbols();
|
||||
var allSymbols = spotSymbols.Concat(futuresSymbols).ToArray();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, allSymbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, allSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "BTC");
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Env", null, "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result.Length, Is.GreaterThanOrEqualTo(2));
|
||||
@@ -451,15 +451,119 @@ namespace CryptoExchange.Net.UnitTests
|
||||
new SharedSpotSymbol("ETH", "BTC", "ETHBTC", true, TradingMode.Spot),
|
||||
new SharedSpotSymbol("ETH", "EUR", "ETHEUR", true, TradingMode.Spot)
|
||||
};
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Env", null, symbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "ETH");
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Env", null, "ETH");
|
||||
|
||||
// assert
|
||||
Assert.That(result.Length, Is.EqualTo(3));
|
||||
Assert.That(result.All(x => x.BaseAsset == "ETH"), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSymbolsForBaseAsset_WithDifferentEnvironments_Should_ReturnNone()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic1";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", null, spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Test", null, "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result.Length, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSymbolsForBaseAsset_WithDifferentKey_Should_ReturnNone()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic2";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", "1", spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Live", "2", "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result.Length, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSymbolsForBaseAsset_WithSetKey_Should_ReturnNone()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic3";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", null, spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Live", "2", "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result.Length, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetSymbolsForBaseAsset_WithNotSetKey_Should_ReturnNone()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic4";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", "2", spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "Live", null, "BTC");
|
||||
|
||||
// assert
|
||||
Assert.That(result.Length, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseSymbol_WithDifferentKey_Should_ReturnNull()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic5";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", "1", spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "Live", "2", "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseSymbol_WithSetKey_Should_ReturnNull()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic6";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", null, spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "Live", "2", "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ParseSymbol_WithNotSetKey_Should_ReturnNull()
|
||||
{
|
||||
// arrange
|
||||
var topicId = "Topic7";
|
||||
var spotSymbols = CreateTestSymbols();
|
||||
ExchangeSymbolCache.UpdateSymbolInfo(topicId, "Live", "1", spotSymbols);
|
||||
|
||||
// act
|
||||
var result = ExchangeSymbolCache.ParseSymbol(topicId, "Live", null, "BTCUSDT");
|
||||
|
||||
// assert
|
||||
Assert.That(result, Is.Not.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,15 +11,15 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
{
|
||||
public TestQuery(TestSocketMessage request, bool authenticated) : base(request, authenticated, 1)
|
||||
{
|
||||
MessageRouter = MessageRouter.CreateWithoutTopicFilter<TestSocketMessage>(request.Id.ToString(), HandleMessage);
|
||||
MessageRouter = MessageRouter.CreateForQuery<TestSocketMessage>(request.Id.ToString(), HandleMessage);
|
||||
}
|
||||
|
||||
private CallResult? HandleMessage(SocketConnection connection, DateTime time, string? arg3, TestSocketMessage message)
|
||||
private CallResult<TestSocketMessage>? HandleMessage(SocketConnection connection, DateTime time, string? arg3, TestSocketMessage message)
|
||||
{
|
||||
if (message.Data != "OK")
|
||||
return new CallResult(new ServerError(ErrorInfo.Unknown with { Message = message.Data }));
|
||||
return CallResult.Fail<TestSocketMessage>(new ServerError(ErrorInfo.Unknown with { Message = message.Data }));
|
||||
|
||||
return CallResult.SuccessResult;
|
||||
return CallResult.Ok(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
{
|
||||
protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler();
|
||||
|
||||
public TestRestApiClient(ILogger logger, HttpClient? httpClient, TestRestOptions options)
|
||||
: base(logger, httpClient, options.Environment.RestClientAddress, options, options.ExchangeOptions)
|
||||
public TestRestApiClient(ILoggerFactory? loggerFactory, HttpClient? httpClient, TestRestOptions options)
|
||||
: base(loggerFactory, "Test", httpClient, options.Environment.RestClientAddress, options, options.ExchangeOptions)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,14 +48,14 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
RequestFactory = factory;
|
||||
}
|
||||
|
||||
internal async Task<WebCallResult<T>> GetResponseAsync<T>(HttpMethod? httpMethod = null, ParameterCollection? collection = null, RateLimitGate? rateLimitGate = null)
|
||||
internal async Task<HttpResult<T>> GetResponseAsync<T>(HttpMethod? httpMethod = null, Parameters? collection = null, RateLimitGate? rateLimitGate = null)
|
||||
{
|
||||
var definition = new RequestDefinition("/path", httpMethod ?? HttpMethod.Get)
|
||||
var definition = new RequestDefinition(BaseAddress, "/path", httpMethod ?? HttpMethod.Get)
|
||||
{
|
||||
Weight = rateLimitGate == null ? 0 : 1,
|
||||
RateLimitGate = rateLimitGate
|
||||
};
|
||||
return await SendAsync<T>(BaseAddress, definition, collection ?? new ParameterCollection(), default);
|
||||
return await SendAsync<T>(definition, collection ?? new Parameters(new ParameterSerializationSettings()), default);
|
||||
}
|
||||
|
||||
internal void SetParameterPosition(HttpMethod httpMethod, HttpMethodParameterPosition pos)
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
{
|
||||
Initialize(options.Value);
|
||||
|
||||
ApiClient1 = AddApiClient(new TestRestApiClient(_logger, httpClient, options.Value));
|
||||
ApiClient2 = AddApiClient(new TestRestApiClient(_logger, httpClient, options.Value));
|
||||
ApiClient1 = AddApiClient(new TestRestApiClient(loggerFactory, httpClient, options.Value));
|
||||
ApiClient2 = AddApiClient(new TestRestApiClient(loggerFactory, httpClient, options.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using CryptoExchange.Net.UnitTests.ConverterTests;
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.UnitTests.ConverterTests;
|
||||
using CryptoExchange.Net.UnitTests.Implementations;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
@@ -11,6 +12,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
[JsonSerializable(typeof(IDictionary<string, string>))]
|
||||
[JsonSerializable(typeof(Dictionary<string, object>))]
|
||||
[JsonSerializable(typeof(IDictionary<string, object>))]
|
||||
[JsonSerializable(typeof(Parameters))]
|
||||
[JsonSerializable(typeof(TestObject))]
|
||||
|
||||
[JsonSerializable(typeof(TestSocketMessage))]
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
{
|
||||
internal class TestSocketApiClient : SocketApiClient<TestEnvironment, TestAuthenticationProvider, TestCredentials>
|
||||
{
|
||||
public TestSocketApiClient(ILogger logger, TestSocketOptions options)
|
||||
: base(logger, options.Environment.SocketClientAddress, options, options.ExchangeOptions)
|
||||
public TestSocketApiClient(ILoggerFactory? loggerFactory, TestSocketOptions options)
|
||||
: base(loggerFactory, "Test", options.Environment.SocketClientAddress, options, options.ExchangeOptions)
|
||||
{
|
||||
}
|
||||
|
||||
public TestSocketApiClient(ILogger logger, HttpClient httpClient, string baseAddress, TestSocketOptions options, SocketApiOptions apiOptions)
|
||||
: base(logger, baseAddress, options, apiOptions)
|
||||
public TestSocketApiClient(ILoggerFactory? loggerFactory, HttpClient httpClient, string baseAddress, TestSocketOptions options, SocketApiOptions apiOptions)
|
||||
: base(loggerFactory, "Test", baseAddress, options, apiOptions)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
protected override TestAuthenticationProvider CreateAuthenticationProvider(TestCredentials credentials) =>
|
||||
new TestAuthenticationProvider(credentials);
|
||||
|
||||
public async Task<CallResult<UpdateSubscription>> SubscribeToUpdatesAsync<T>(Action<DataEvent<T>> handler, bool subQuery, CancellationToken ct)
|
||||
public async Task<WebSocketResult<UpdateSubscription>> SubscribeToUpdatesAsync<T>(Action<DataEvent<T>> handler, bool subQuery, CancellationToken ct)
|
||||
{
|
||||
return await base.SubscribeAsync(new TestSubscription<T>(_logger, handler, subQuery, false), ct);
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
{
|
||||
Initialize(options.Value);
|
||||
|
||||
ApiClient1 = AddApiClient(new TestSocketApiClient(_logger, options.Value));
|
||||
ApiClient2 = AddApiClient(new TestSocketApiClient(_logger, options.Value));
|
||||
ApiClient1 = AddApiClient(new TestSocketApiClient(loggerFactory, options.Value));
|
||||
ApiClient2 = AddApiClient(new TestSocketApiClient(loggerFactory, options.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
_handler = handler;
|
||||
_subQuery = subQuery;
|
||||
|
||||
MessageRouter = MessageRouter.CreateWithoutTopicFilter<T>("test", HandleUpdate);
|
||||
MessageRouter = MessageRouter.CreateForEvent<T>("test", HandleUpdate);
|
||||
}
|
||||
|
||||
protected override Query? GetSubQuery(SocketConnection connection)
|
||||
@@ -44,7 +44,7 @@ namespace CryptoExchange.Net.UnitTests.Implementations
|
||||
private CallResult? HandleUpdate(SocketConnection connection, DateTime time, string? originalData, T data)
|
||||
{
|
||||
_handler(new DataEvent<T>("Test", data, time, originalData));
|
||||
return CallResult.SuccessResult;
|
||||
return CallResult.Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,319 +12,248 @@ namespace CryptoExchange.Net.UnitTests
|
||||
[Test]
|
||||
public void AddingBasicValue_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", "value");
|
||||
Assert.That(parameters["test"], Is.EqualTo("value"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingBasicNullValue_ThrowsException()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
Assert.Throws<ArgumentNullException>(() => parameters.Add("test", null!));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalBasicValue_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptional("test", "value");
|
||||
Assert.That(parameters["test"], Is.EqualTo("value"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalBasicNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptional("test", null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingDecimalValueAsString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddString("test", 0.1m);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", 0.1m, DecimalSerialization.String);
|
||||
Assert.That(parameters["test"], Is.EqualTo("0.1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalDecimalValueAsString_SetValueCorrectly()
|
||||
public void AddingDecimalValueAsString2_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalString("test", 0.1m);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
Decimal = DecimalSerialization.String
|
||||
});
|
||||
parameters.Add("test", 0.1m);
|
||||
Assert.That(parameters["test"], Is.EqualTo("0.1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalDecimalNullValueAsString_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalString("test", (decimal?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingIntValueAsString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddString("test", 1);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalIntValueAsString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalString("test", 1);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalIntNullValueAsString_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalString("test", (int?)null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", (int?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingLongValueAsString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddString("test", 1L);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", 1L, IntegerSerialization.String);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalLongValueAsString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalString("test", 1L);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
Integer = IntegerSerialization.String
|
||||
});
|
||||
parameters.Add("test", 1L);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalLongNullValueAsString_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalString("test", (long?)null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", (long?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingMillisecondTimestamp_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddMilliseconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), DateTimeSerialization.MillisecondsNumber);
|
||||
Assert.That(parameters["test"], Is.EqualTo(1735689600000));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalMillisecondTimestamp_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalMilliseconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
DateTimes = DateTimeSerialization.MillisecondsNumber
|
||||
});
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
Assert.That(parameters["test"], Is.EqualTo(1735689600000));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalMillisecondNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalMilliseconds("test", null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", (DateTime?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingMillisecondTimestampString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddMillisecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), DateTimeSerialization.MillisecondsString);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1735689600000"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalMillisecondTimestampString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalMillisecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
DateTimes = DateTimeSerialization.MillisecondsString
|
||||
});
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
Assert.That(parameters["test"], Is.EqualTo("1735689600000"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalMillisecondStringNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalMillisecondsString("test", null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingSecondTimestamp_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddSeconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), DateTimeSerialization.SecondsNumber);
|
||||
Assert.That(parameters["test"], Is.EqualTo(1735689600));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalSecondTimestamp_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalSeconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
DateTimes = DateTimeSerialization.SecondsNumber
|
||||
});
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
Assert.That(parameters["test"], Is.EqualTo(1735689600));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingSecondNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalSeconds("test", null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingSecondTimestampString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddSecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), DateTimeSerialization.SecondsString);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1735689600"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalSecondTimestampString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalSecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
DateTimes = DateTimeSerialization.SecondsString
|
||||
});
|
||||
parameters.Add("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
Assert.That(parameters["test"], Is.EqualTo("1735689600"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingSecondStringNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalSecondsString("test", null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingEnum_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddEnum("test", TestEnum.Two);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", TestEnum.Two);
|
||||
Assert.That(parameters["test"], Is.EqualTo("2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalEnum_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalEnum("test", (TestEnum?)TestEnum.Two);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", (TestEnum?)TestEnum.Two);
|
||||
Assert.That(parameters["test"], Is.EqualTo("2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalEnumNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalEnum("test", (TestEnum?)null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", (TestEnum?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingEnumAsInt_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddEnumAsInt("test", TestEnum.Two);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", TestEnum.Two, EnumSerialization.Number);
|
||||
Assert.That(parameters["test"], Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalEnumAsInt_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalEnumAsInt("test", (TestEnum?)TestEnum.Two);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
Enum = EnumSerialization.Number
|
||||
});
|
||||
parameters.Add("test", TestEnum.Two);
|
||||
Assert.That(parameters["test"], Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalEnumAsIntNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalEnumAsInt("test", (TestEnum?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingCommaSeparated_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.AddCommaSeparated("test", ["1", "2"]);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1,2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalCommaSeparated_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalCommaSeparated("test", ["1", "2"]);
|
||||
Assert.That(parameters["test"], Is.EqualTo("1,2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalCommaSeparatedNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalCommaSeparated("test", (string[]?)null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.AddCommaSeparated("test", (string[]?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingCommaSeparatedEnum_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.AddCommaSeparated("test", [TestEnum.Two, TestEnum.One]);
|
||||
Assert.That(parameters["test"], Is.EqualTo("2,1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalCommaSeparatedEnum_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalCommaSeparated("test", [TestEnum.Two, TestEnum.One]);
|
||||
Assert.That(parameters["test"], Is.EqualTo("2,1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalCommaSeparatedEnumNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalCommaSeparated("test", (TestEnum[]?)null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingBoolString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddBoolString("test", true);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", true, BoolSerialization.String);
|
||||
Assert.That(parameters["test"], Is.EqualTo("true"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalBoolString_SetValueCorrectly()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalBoolString("test", true);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings()
|
||||
{
|
||||
Bool = BoolSerialization.String
|
||||
});
|
||||
parameters.Add("test", true);
|
||||
Assert.That(parameters["test"], Is.EqualTo("true"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddingOptionalBoolStringNullValue_DoesntSetValue()
|
||||
{
|
||||
var parameters = new ParameterCollection();
|
||||
parameters.AddOptionalBoolString("test", null);
|
||||
var parameters = new Parameters(new ParameterSerializationSettings());
|
||||
parameters.Add("test", null);
|
||||
Assert.That(parameters.ContainsKey("test"), Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,16 +29,16 @@ namespace CryptoExchange.Net.UnitTests
|
||||
|
||||
var triggered = false;
|
||||
rateLimiter.RateLimitTriggered += (x) => { triggered = true; };
|
||||
var requestDefinition = new RequestDefinition("/sapi/v1/system/status", HttpMethod.Get);
|
||||
var requestDefinition = new RequestDefinition("https://test.com", "/sapi/v1/system/status", HttpMethod.Get);
|
||||
|
||||
for (var i = 0; i < requests + 1; i++)
|
||||
{
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(i == requests ? triggered : !triggered);
|
||||
}
|
||||
triggered = false;
|
||||
await Task.Delay((int)Math.Round(perSeconds * 1000) + 10);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(!triggered);
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new PathStartFilter("/sapi/"), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
|
||||
|
||||
var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get);
|
||||
var requestDefinition = new RequestDefinition("https://test.com", endpoint, HttpMethod.Get);
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
bool expected = i == 1 ? expectLimiting ? evnt?.DelayTime > TimeSpan.Zero : evnt == null : evnt == null;
|
||||
Assert.That(expected);
|
||||
}
|
||||
@@ -73,15 +73,15 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new PathStartFilter("/sapi/"), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
|
||||
|
||||
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get);
|
||||
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get);
|
||||
var requestDefinition1 = new RequestDefinition("https://test.com", endpoint1, HttpMethod.Get);
|
||||
var requestDefinition2 = new RequestDefinition("https://test.com", endpoint2, HttpMethod.Get);
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(evnt == null);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(expectLimiting ? evnt != null : evnt == null);
|
||||
}
|
||||
|
||||
@@ -96,16 +96,16 @@ namespace CryptoExchange.Net.UnitTests
|
||||
|
||||
bool triggered = false;
|
||||
rateLimiter.RateLimitTriggered += (x) => { triggered = true; };
|
||||
var requestDefinition = new RequestDefinition("/sapi/test", HttpMethod.Get);
|
||||
var requestDefinition = new RequestDefinition("https://test.com", "/sapi/test", HttpMethod.Get);
|
||||
|
||||
for (var i = 0; i < requests + 1; i++)
|
||||
{
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(i == requests ? triggered : !triggered);
|
||||
}
|
||||
triggered = false;
|
||||
await Task.Delay((int)Math.Round(perSeconds * 1000) + 10);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(!triggered);
|
||||
}
|
||||
|
||||
@@ -117,13 +117,13 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new ExactPathFilter("/sapi/test"), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
|
||||
|
||||
var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get);
|
||||
var requestDefinition = new RequestDefinition("https://test.com", endpoint, HttpMethod.Get);
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
bool expected = i == 1 ? expectLimited ? evnt?.DelayTime > TimeSpan.Zero : evnt == null : evnt == null;
|
||||
Assert.That(expected);
|
||||
}
|
||||
@@ -137,13 +137,13 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new ExactPathsFilter(new[] { "/sapi/test", "/sapi/test2" }), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
|
||||
var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get);
|
||||
var requestDefinition = new RequestDefinition("https://test.com", endpoint, HttpMethod.Get);
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
bool expected = i == 1 ? expectLimited ? evnt?.DelayTime > TimeSpan.Zero : evnt == null : evnt == null;
|
||||
Assert.That(expected);
|
||||
}
|
||||
@@ -160,15 +160,15 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerApiKey, new AuthenticatedEndpointFilter(true), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Sliding));
|
||||
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get) { Authenticated = key1 != null };
|
||||
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = key2 != null };
|
||||
var requestDefinition1 = new RequestDefinition("https://test.com", endpoint1, HttpMethod.Get) { Authenticated = key1 != null };
|
||||
var requestDefinition2 = new RequestDefinition("https://test.com", endpoint2, HttpMethod.Get) { Authenticated = key2 != null };
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", key1, 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, key1, 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(evnt == null);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, "https://test.com", key2, 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, key2, 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(expectLimited ? evnt != null : evnt == null);
|
||||
}
|
||||
|
||||
@@ -179,15 +179,15 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, Array.Empty<IGuardFilter>(), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
|
||||
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get);
|
||||
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = true };
|
||||
var requestDefinition1 = new RequestDefinition("https://test.com", endpoint1, HttpMethod.Get);
|
||||
var requestDefinition2 = new RequestDefinition("https://test.com", endpoint2, HttpMethod.Get) { Authenticated = true };
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(evnt == null);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, "https://test.com", null, 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, null, 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(expectLimited ? evnt != null : evnt == null);
|
||||
}
|
||||
|
||||
@@ -199,15 +199,15 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new HostFilter("https://test.com"), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
|
||||
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get);
|
||||
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = true };
|
||||
var requestDefinition1 = new RequestDefinition(host1, endpoint1, HttpMethod.Get);
|
||||
var requestDefinition2 = new RequestDefinition(host2, endpoint2, HttpMethod.Get) { Authenticated = true };
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, host1, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(evnt == null);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, host2, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition2, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(expectLimited ? evnt != null : evnt == null);
|
||||
}
|
||||
|
||||
@@ -222,9 +222,9 @@ namespace CryptoExchange.Net.UnitTests
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("1", HttpMethod.Get), host1, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition(host1, "1", HttpMethod.Get), "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(evnt == null);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("1", HttpMethod.Get), host2, "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition(host2, "1", HttpMethod.Get), "123", 1, RateLimitingBehaviour.Wait, null, default);
|
||||
Assert.That(expectLimited ? evnt != null : evnt == null);
|
||||
}
|
||||
|
||||
@@ -238,8 +238,8 @@ namespace CryptoExchange.Net.UnitTests
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(0.2));
|
||||
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("1", HttpMethod.Get), "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, ct.Token);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("1", HttpMethod.Get), "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, ct.Token);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("https://test.com", "1", HttpMethod.Get), "123", 1, RateLimitingBehaviour.Wait, null, ct.Token);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("https://test.com", "1", HttpMethod.Get), "123", 1, RateLimitingBehaviour.Wait, null, ct.Token);
|
||||
Assert.That(result2.Error, Is.TypeOf<CancellationRequestedError>());
|
||||
}
|
||||
|
||||
@@ -250,16 +250,16 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerConnection, new LimitItemTypeFilter(RateLimitItemType.Request), 1, TimeSpan.FromSeconds(10), RateLimitWindowType.Fixed));
|
||||
|
||||
var definition = new RequestDefinition("1", HttpMethod.Get) { ConnectionId = 1 };
|
||||
var definition = new RequestDefinition("https://test.com", "1", HttpMethod.Get) { ConnectionId = 1 };
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(0.2));
|
||||
|
||||
// act
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition, "https://test.com", null, 1, RateLimitingBehaviour.Fail, null, ct.Token);
|
||||
await rateLimiter.ResetAsync(RateLimitItemType.Request, definition, "https://test.com", null, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition, "https://test.com", null, 1, RateLimitingBehaviour.Fail, null, ct.Token);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition, null, 1, RateLimitingBehaviour.Fail, null, ct.Token);
|
||||
await rateLimiter.ResetAsync(RateLimitItemType.Request, definition, null, null, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition, null, 1, RateLimitingBehaviour.Fail, null, ct.Token);
|
||||
|
||||
// assert
|
||||
Assert.That(evnt, Is.Null);
|
||||
@@ -272,17 +272,17 @@ namespace CryptoExchange.Net.UnitTests
|
||||
var rateLimiter = new RateLimitGate("Test");
|
||||
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerConnection, new LimitItemTypeFilter(RateLimitItemType.Request), 1, TimeSpan.FromSeconds(10), RateLimitWindowType.Fixed));
|
||||
|
||||
var definition1 = new RequestDefinition("1", HttpMethod.Get) { ConnectionId = 1 };
|
||||
var definition2 = new RequestDefinition("2", HttpMethod.Get) { ConnectionId = 2 };
|
||||
var definition1 = new RequestDefinition("https://test.com", "1", HttpMethod.Get) { ConnectionId = 1 };
|
||||
var definition2 = new RequestDefinition("https://test.com", "2", HttpMethod.Get) { ConnectionId = 2 };
|
||||
|
||||
RateLimitEvent? evnt = null;
|
||||
rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
|
||||
|
||||
// act
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition1, "https://test.com", null, 1, RateLimitingBehaviour.Fail, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition2, "https://test.com", null, 1, RateLimitingBehaviour.Fail, null, default);
|
||||
await rateLimiter.ResetAsync(RateLimitItemType.Request, definition1, "https://test.com", null, null, default);
|
||||
var result3 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition2, "https://test.com", null, 1, RateLimitingBehaviour.Fail, null, default);
|
||||
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition1, null, 1, RateLimitingBehaviour.Fail, null, default);
|
||||
var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition2, null, 1, RateLimitingBehaviour.Fail, null, default);
|
||||
await rateLimiter.ResetAsync(RateLimitItemType.Request, definition1, null, null, null, default);
|
||||
var result3 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, definition2, null, 1, RateLimitingBehaviour.Fail, null, default);
|
||||
|
||||
// assert
|
||||
Assert.That(evnt, Is.Not.Null);
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var routes = new MessageRoute[]
|
||||
{
|
||||
MessageRoute<string>.CreateWithoutTopicFilter("type1", (_, _, _, _) => null),
|
||||
MessageRoute<string>.CreateWithTopicFilter("type1", "topic1", (_, _, _, _) => null),
|
||||
MessageRoute<int>.CreateWithTopicFilter("type2", "topic2", (_, _, _, _) => null)
|
||||
MessageRoute.CreateForEvent<string>("type1", (_, _, _, _) => null),
|
||||
MessageRoute.CreateForEvent<string>("type1", "topic1", (_, _, _, _) => null),
|
||||
MessageRoute.CreateForEvent<int>("type2", "topic2", (_, _, _, _) => null)
|
||||
};
|
||||
|
||||
var router = new QueryRouter(routes);
|
||||
@@ -46,10 +46,10 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
|
||||
// act
|
||||
collection.AddRoute(null, MessageRoute<string>.CreateWithoutTopicFilter("type", (_, _, _, _) => null));
|
||||
collection.AddRoute(null, MessageRoute.CreateForEvent<string>("type", (_, _, _, _) => null));
|
||||
var beforeMultipleReaders = collection.MultipleReaders;
|
||||
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) => null, true));
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) => null, true));
|
||||
var afterMultipleReaders = collection.MultipleReaders;
|
||||
|
||||
// assert
|
||||
@@ -63,12 +63,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute(null, MessageRoute<string>.CreateWithoutTopicFilter("type", (_, _, _, _) =>
|
||||
collection.AddRoute(null, MessageRoute.CreateForEvent<string>("type", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("no-topic");
|
||||
return null;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("topic");
|
||||
return null;
|
||||
@@ -89,7 +89,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
{
|
||||
// arrange
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute("other-topic", MessageRoute<string>.CreateWithTopicFilter("type", "other-topic", (_, _, _, _) => null));
|
||||
collection.AddRoute("other-topic", MessageRoute.CreateForEvent<string>("type", "other-topic", (_, _, _, _) => null));
|
||||
collection.Build();
|
||||
|
||||
// act
|
||||
@@ -106,12 +106,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute(null, MessageRoute<string>.CreateWithoutTopicFilter("type", (_, _, _, _) =>
|
||||
collection.AddRoute(null, MessageRoute.CreateForEvent<string>("type", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("no-topic");
|
||||
return null;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("topic");
|
||||
return null;
|
||||
@@ -132,17 +132,17 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
{
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var expectedResult = CallResult.SuccessResult;
|
||||
var expectedResult = CallResult.Ok();
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("first");
|
||||
return expectedResult;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("second");
|
||||
return new CallResult(null);
|
||||
return CallResult.Ok();
|
||||
}));
|
||||
collection.Build();
|
||||
|
||||
@@ -160,17 +160,17 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
{
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var expectedResult = CallResult.SuccessResult;
|
||||
var expectedResult = CallResult.Ok();
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("first");
|
||||
return expectedResult;
|
||||
}, true));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("second");
|
||||
return new CallResult(null);
|
||||
return CallResult.Ok();
|
||||
}));
|
||||
collection.Build();
|
||||
|
||||
@@ -188,22 +188,22 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
{
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var expectedResult = CallResult.SuccessResult;
|
||||
var expectedResult = CallResult.Ok();
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("first");
|
||||
return null;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("second");
|
||||
return expectedResult;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("third");
|
||||
return new CallResult(null);
|
||||
return CallResult.Ok();
|
||||
}));
|
||||
collection.Build();
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
{
|
||||
// arrange
|
||||
var collection = new QueryRouteCollection(typeof(string));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) => null));
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) => null));
|
||||
collection.Build();
|
||||
|
||||
// act
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
var processor1 = new TestMessageProcessor(
|
||||
1,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<string>.CreateWithoutTopicFilter("type1", (_, _, _, _) => null),
|
||||
MessageRoute<string>.CreateWithTopicFilter("type1", "topic1", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<string>("type1", (_, _, _, _) => null),
|
||||
MessageRoute.CreateForEvent<string>("type1", "topic1", (_, _, _, _) => null)));
|
||||
|
||||
var processor2 = new TestMessageProcessor(
|
||||
2,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<int>.CreateWithTopicFilter("type2", "topic2", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<int>("type2", "topic2", (_, _, _, _) => null)));
|
||||
|
||||
var table = new RoutingTable();
|
||||
|
||||
@@ -57,12 +57,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
var processor1 = new TestMessageProcessor(
|
||||
1,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<string>.CreateWithoutTopicFilter("type1", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<string>("type1", (_, _, _, _) => null)));
|
||||
|
||||
var processor2 = new TestMessageProcessor(
|
||||
2,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<string>.CreateWithTopicFilter("type1", "topic1", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<string>("type1", "topic1", (_, _, _, _) => null)));
|
||||
|
||||
var table = new RoutingTable();
|
||||
|
||||
@@ -85,12 +85,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
var initialProcessor = new TestMessageProcessor(
|
||||
1,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<string>.CreateWithoutTopicFilter("type1", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<string>("type1", (_, _, _, _) => null)));
|
||||
|
||||
var replacementProcessor = new TestMessageProcessor(
|
||||
2,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<int>.CreateWithoutTopicFilter("type2", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<int>("type2", (_, _, _, _) => null)));
|
||||
|
||||
var table = new RoutingTable();
|
||||
table.Update(new IMessageProcessor[] { initialProcessor });
|
||||
@@ -116,7 +116,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
var processor = new TestMessageProcessor(
|
||||
1,
|
||||
MessageRouter.Create(
|
||||
MessageRoute<string>.CreateWithoutTopicFilter("type1", (_, _, _, _) => null)));
|
||||
MessageRoute.CreateForEvent<string>("type1", (_, _, _, _) => null)));
|
||||
|
||||
var table = new RoutingTable();
|
||||
table.Update(new IMessageProcessor[] { processor });
|
||||
|
||||
@@ -15,9 +15,9 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var routes = new MessageRoute[]
|
||||
{
|
||||
MessageRoute<string>.CreateWithoutTopicFilter("type1", (_, _, _, _) => null),
|
||||
MessageRoute<string>.CreateWithTopicFilter("type1", "topic1", (_, _, _, _) => null),
|
||||
MessageRoute<int>.CreateWithTopicFilter("type2", "topic2", (_, _, _, _) => null)
|
||||
MessageRoute.CreateForEvent<string>("type1", (_, _, _, _) => null),
|
||||
MessageRoute.CreateForEvent<string>("type1", "topic1", (_, _, _, _) => null),
|
||||
MessageRoute.CreateForEvent<int>("type2", "topic2", (_, _, _, _) => null)
|
||||
};
|
||||
|
||||
var router = new SubscriptionRouter(routes);
|
||||
@@ -44,12 +44,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var collection = new SubscriptionRouteCollection(typeof(string));
|
||||
collection.AddRoute(null, MessageRoute<string>.CreateWithoutTopicFilter("type", (_, _, _, _) =>
|
||||
collection.AddRoute(null, MessageRoute.CreateForEvent<string>("type", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("no-topic");
|
||||
return null;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("topic");
|
||||
return null;
|
||||
@@ -61,7 +61,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
|
||||
// assert
|
||||
Assert.That(handled, Is.True);
|
||||
Assert.That(result, Is.SameAs(CallResult.SuccessResult));
|
||||
Assert.That(result, Is.SameAs(CallResult.Ok()));
|
||||
Assert.That(calls, Is.EqualTo(new[] { "no-topic" }));
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
{
|
||||
// arrange
|
||||
var collection = new SubscriptionRouteCollection(typeof(string));
|
||||
collection.AddRoute("other-topic", MessageRoute<string>.CreateWithTopicFilter("type", "other-topic", (_, _, _, _) => null));
|
||||
collection.AddRoute("other-topic", MessageRoute.CreateForEvent<string>("type", "other-topic", (_, _, _, _) => null));
|
||||
collection.Build();
|
||||
|
||||
// act
|
||||
@@ -78,7 +78,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
|
||||
// assert
|
||||
Assert.That(handled, Is.False);
|
||||
Assert.That(result, Is.SameAs(CallResult.SuccessResult));
|
||||
Assert.That(result, Is.SameAs(CallResult.Ok()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -87,12 +87,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var collection = new SubscriptionRouteCollection(typeof(string));
|
||||
collection.AddRoute(null, MessageRoute<string>.CreateWithoutTopicFilter("type", (_, _, _, _) =>
|
||||
collection.AddRoute(null, MessageRoute.CreateForEvent<string>("type", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("no-topic");
|
||||
return null;
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("topic");
|
||||
return null;
|
||||
@@ -104,7 +104,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
|
||||
// assert
|
||||
Assert.That(handled, Is.True);
|
||||
Assert.That(result, Is.SameAs(CallResult.SuccessResult));
|
||||
Assert.That(result, Is.SameAs(CallResult.Ok()));
|
||||
Assert.That(calls, Is.EqualTo(new[] { "no-topic", "topic" }));
|
||||
}
|
||||
|
||||
@@ -114,12 +114,12 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var collection = new SubscriptionRouteCollection(typeof(string));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("first");
|
||||
return CallResult.SuccessResult;
|
||||
return CallResult.Ok();
|
||||
}));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("second");
|
||||
return null;
|
||||
@@ -131,7 +131,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
|
||||
// assert
|
||||
Assert.That(handled, Is.True);
|
||||
Assert.That(result, Is.SameAs(CallResult.SuccessResult));
|
||||
Assert.That(result, Is.SameAs(CallResult.Ok()));
|
||||
Assert.That(calls, Is.EqualTo(new[] { "first", "second" }));
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
// arrange
|
||||
var calls = new List<string>();
|
||||
var collection = new SubscriptionRouteCollection(typeof(string));
|
||||
collection.AddRoute("topic", MessageRoute<string>.CreateWithTopicFilter("type", "topic", (_, _, _, _) =>
|
||||
collection.AddRoute("topic", MessageRoute.CreateForEvent<string>("type", "topic", (_, _, _, _) =>
|
||||
{
|
||||
calls.Add("topic");
|
||||
return null;
|
||||
@@ -153,7 +153,7 @@ namespace CryptoExchange.Net.UnitTests.SocketRoutingTests
|
||||
|
||||
// assert
|
||||
Assert.That(handled, Is.False);
|
||||
Assert.That(result, Is.SameAs(CallResult.SuccessResult));
|
||||
Assert.That(result, Is.SameAs(CallResult.Ok()));
|
||||
Assert.That(calls, Is.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
}
|
||||
|
||||
|
||||
protected override Task<CallResult<bool>> DoResyncAsync(CancellationToken ct)
|
||||
protected override Task<CallResult> DoResyncAsync(CancellationToken ct)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.Objects.Errors;
|
||||
using CryptoExchange.Net.Sockets;
|
||||
using CryptoExchange.Net.Sockets.Default;
|
||||
using CryptoExchange.Net.TokenManagement;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TokenManagementTests
|
||||
{
|
||||
private static readonly TimeSpan TestMaintenanceInterval = TimeSpan.FromMilliseconds(5);
|
||||
|
||||
[Test]
|
||||
public async Task AcquireWithoutApiKeyReturnsCredentialsError()
|
||||
{
|
||||
var starts = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) =>
|
||||
{
|
||||
starts++;
|
||||
return Task.FromResult(CallResult.Ok("token"));
|
||||
});
|
||||
|
||||
var result = await manager.AcquireAsync(new TokenScope("Test", "Test", "Test", ""));
|
||||
|
||||
Assert.That(result.Success, Is.False);
|
||||
Assert.That(result.Error, Is.TypeOf<NoApiCredentialsError>());
|
||||
Assert.That(starts, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task StartTokenFailureIsReturned()
|
||||
{
|
||||
var error = new ServerError(ErrorType.Unknown, "start failed");
|
||||
var manager = CreateManager((_, _) => Task.FromResult(CallResult.Fail<string>(error)));
|
||||
|
||||
var result = await manager.AcquireAsync(CreateScope());
|
||||
|
||||
Assert.That(result.Success, Is.False);
|
||||
Assert.That(result.Error, Is.SameAs(error));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ActiveTokenIsSharedWhileLeasedAndStoppedAfterLastRelease()
|
||||
{
|
||||
var starts = 0;
|
||||
var stops = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
stopToken: (_, _) =>
|
||||
{
|
||||
stops++;
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
});
|
||||
var scope = CreateScope();
|
||||
|
||||
var first = await manager.AcquireAsync(scope);
|
||||
var second = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(first);
|
||||
AssertSuccess(second);
|
||||
|
||||
Assert.That(second.Data!.Token.Token, Is.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(starts, Is.EqualTo(1));
|
||||
|
||||
await first.Data!.ReleaseAsync();
|
||||
Assert.That(stops, Is.EqualTo(0));
|
||||
|
||||
await second.Data!.ReleaseAsync();
|
||||
Assert.That(stops, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ActiveTokenStartsNewTokenAfterLeaseRelease()
|
||||
{
|
||||
var starts = 0;
|
||||
var stops = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
stopToken: (_, _) =>
|
||||
{
|
||||
stops++;
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
});
|
||||
var scope = CreateScope();
|
||||
|
||||
var first = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(first);
|
||||
await first.Data!.ReleaseAsync();
|
||||
var second = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(second);
|
||||
|
||||
Assert.That(second.Data!.Token.Token, Is.Not.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(starts, Is.EqualTo(2));
|
||||
Assert.That(stops, Is.EqualTo(1));
|
||||
await second.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ReleasingLeaseTwiceOnlyStopsActiveTokenOnce()
|
||||
{
|
||||
var stops = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token")),
|
||||
stopToken: (_, _) =>
|
||||
{
|
||||
stops++;
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
});
|
||||
|
||||
var leaseResult = await manager.AcquireAsync(CreateScope());
|
||||
AssertSuccess(leaseResult);
|
||||
|
||||
await leaseResult.Data!.ReleaseAsync();
|
||||
await leaseResult.Data!.ReleaseAsync();
|
||||
|
||||
Assert.That(stops, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CachedTokenIsReusedAfterLeaseRelease()
|
||||
{
|
||||
var starts = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
managementType: TokenManagementType.Cached);
|
||||
var scope = CreateScope();
|
||||
|
||||
var first = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(first);
|
||||
await first.Data!.ReleaseAsync();
|
||||
var second = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(second);
|
||||
|
||||
Assert.That(second.Data!.Token.Token, Is.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(starts, Is.EqualTo(1));
|
||||
await second.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CachedTokensAreScopedIndependently()
|
||||
{
|
||||
var starts = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
managementType: TokenManagementType.Cached);
|
||||
|
||||
var firstScope = CreateScope(additionalIdentifier: "one");
|
||||
var secondScope = CreateScope(additionalIdentifier: "two");
|
||||
|
||||
var first = await manager.AcquireAsync(firstScope);
|
||||
var second = await manager.AcquireAsync(secondScope);
|
||||
AssertSuccess(first);
|
||||
AssertSuccess(second);
|
||||
await first.Data!.ReleaseAsync();
|
||||
await second.Data!.ReleaseAsync();
|
||||
|
||||
var firstAgain = await manager.AcquireAsync(firstScope);
|
||||
AssertSuccess(firstAgain);
|
||||
|
||||
Assert.That(firstAgain.Data!.Token.Token, Is.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(second.Data!.Token.Token, Is.Not.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(starts, Is.EqualTo(2));
|
||||
await firstAgain.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ExpiredCachedTokenIsNotReused()
|
||||
{
|
||||
var starts = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
timeValid: TimeSpan.FromMilliseconds(20),
|
||||
managementType: TokenManagementType.Cached);
|
||||
var scope = CreateScope();
|
||||
|
||||
var first = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(first);
|
||||
await first.Data!.ReleaseAsync();
|
||||
await Task.Delay(50);
|
||||
var second = await manager.AcquireAsync(scope);
|
||||
AssertSuccess(second);
|
||||
|
||||
Assert.That(first.Data!.Token.Status, Is.EqualTo(TokenStatus.Expired));
|
||||
Assert.That(second.Data!.Token.Token, Is.Not.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(starts, Is.EqualTo(2));
|
||||
await second.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task CachedTokenDoesNotRunKeepAliveLoop()
|
||||
{
|
||||
var keepAlives = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token")),
|
||||
refreshInterval: TimeSpan.FromMilliseconds(1),
|
||||
keepAliveToken: (_, _) =>
|
||||
{
|
||||
keepAlives++;
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
},
|
||||
managementType: TokenManagementType.Cached);
|
||||
|
||||
var leaseResult = await manager.AcquireAsync(CreateScope());
|
||||
AssertSuccess(leaseResult);
|
||||
await Task.Delay(50);
|
||||
|
||||
Assert.That(keepAlives, Is.EqualTo(0));
|
||||
await leaseResult.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ActiveTokenKeepAliveRefreshesValidity()
|
||||
{
|
||||
var keepAlives = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token")),
|
||||
refreshInterval: TimeSpan.FromMilliseconds(1),
|
||||
timeValid: TimeSpan.FromSeconds(1),
|
||||
keepAliveToken: (_, _) =>
|
||||
{
|
||||
keepAlives++;
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
});
|
||||
|
||||
var leaseResult = await manager.AcquireAsync(CreateScope());
|
||||
AssertSuccess(leaseResult);
|
||||
var originalValidUntil = leaseResult.Data!.Token.ValidUntil;
|
||||
|
||||
await WaitUntilAsync(() => keepAlives > 0);
|
||||
|
||||
Assert.That(leaseResult.Data!.Token.ValidUntil, Is.GreaterThan(originalValidUntil));
|
||||
await leaseResult.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ActiveTokenKeepAliveFailureExpiresTokenWhenValidityPassed()
|
||||
{
|
||||
var starts = 0;
|
||||
var expired = false;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
refreshInterval: TimeSpan.FromMilliseconds(1),
|
||||
timeValid: TimeSpan.FromMilliseconds(25),
|
||||
keepAliveToken: (_, _) => Task.FromResult(CallResult.Fail(new ServerError(ErrorType.Unknown, "keep alive failed"))));
|
||||
|
||||
var leaseResult = await manager.AcquireAsync(CreateScope());
|
||||
AssertSuccess(leaseResult);
|
||||
leaseResult.Data!.Token.Expired += _ => expired = true;
|
||||
|
||||
await WaitUntilAsync(() => expired);
|
||||
|
||||
Assert.That(leaseResult.Data!.Token.Status, Is.EqualTo(TokenStatus.Expired));
|
||||
|
||||
var nextLease = await manager.AcquireAsync(CreateScope());
|
||||
AssertSuccess(nextLease);
|
||||
Assert.That(nextLease.Data!.Token.Token, Is.Not.EqualTo(leaseResult.Data!.Token.Token));
|
||||
Assert.That(starts, Is.EqualTo(2));
|
||||
|
||||
await leaseResult.Data!.ReleaseAsync();
|
||||
await nextLease.Data!.ReleaseAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task AcquireAndReplaceReleasesPreviousSubscriptionLease()
|
||||
{
|
||||
var starts = 0;
|
||||
var stops = 0;
|
||||
var manager = CreateManager(
|
||||
(_, _) => Task.FromResult(CallResult.Ok("token-" + ++starts)),
|
||||
stopToken: (_, _) =>
|
||||
{
|
||||
stops++;
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
});
|
||||
var subscription = new TestSubscription();
|
||||
|
||||
var first = await manager.AcquireAndReplaceAsync(subscription, CreateScope(additionalIdentifier: "one"));
|
||||
AssertSuccess(first);
|
||||
var second = await manager.AcquireAndReplaceAsync(subscription, CreateScope(additionalIdentifier: "two"));
|
||||
AssertSuccess(second);
|
||||
|
||||
Assert.That(subscription.TokenLease, Is.SameAs(second.Data));
|
||||
Assert.That(second.Data!.Token.Token, Is.Not.EqualTo(first.Data!.Token.Token));
|
||||
Assert.That(stops, Is.EqualTo(1));
|
||||
|
||||
await subscription.TokenLease!.ReleaseAsync();
|
||||
}
|
||||
|
||||
private static TokenManager CreateManager(
|
||||
Func<TokenScope, System.Threading.CancellationToken, Task<CallResult<string>>> startToken,
|
||||
TimeSpan? refreshInterval = null,
|
||||
TimeSpan? timeValid = null,
|
||||
Func<TokenInfo, System.Threading.CancellationToken, Task<CallResult>>? keepAliveToken = null,
|
||||
Func<TokenInfo, System.Threading.CancellationToken, Task<CallResult>>? stopToken = null,
|
||||
TokenManagementType managementType = TokenManagementType.Active)
|
||||
{
|
||||
return new TokenManager(
|
||||
Guid.NewGuid().ToString(),
|
||||
null,
|
||||
refreshInterval ?? TimeSpan.FromMinutes(1),
|
||||
timeValid ?? TimeSpan.FromMinutes(1),
|
||||
startToken,
|
||||
keepAliveToken,
|
||||
stopToken,
|
||||
managementType,
|
||||
TestMaintenanceInterval);
|
||||
}
|
||||
|
||||
private static TokenScope CreateScope(string apiKey = "apiKey", string? additionalIdentifier = null)
|
||||
=> new TokenScope("Test", "Test", "Test", apiKey, additionalIdentifier);
|
||||
|
||||
private static void AssertSuccess(CallResult<TokenLease> result)
|
||||
{
|
||||
Assert.That(result.Success, Is.True, result.Error?.ToString());
|
||||
Assert.That(result.Data, Is.Not.Null);
|
||||
}
|
||||
|
||||
private static async Task WaitUntilAsync(Func<bool> condition)
|
||||
{
|
||||
var timeout = DateTime.UtcNow.AddSeconds(2);
|
||||
while (!condition())
|
||||
{
|
||||
if (DateTime.UtcNow > timeout)
|
||||
Assert.Fail("Condition was not met within the timeout");
|
||||
|
||||
await Task.Delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class TestSubscription : Subscription
|
||||
{
|
||||
public TestSubscription() : base(NullLogger.Instance, true)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Query? GetSubQuery(SocketConnection connection) => null;
|
||||
|
||||
protected override Query? GetUnsubQuery(SocketConnection connection) => null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user