mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2026-04-07 02:01:12 +00:00
Updated API credential logic, exchange implementation are expected to provide their own credentials implementation with ApiCredentials as base class Removed ApiCredentials implementation used by most exchanges Removed ApiCredentialsType Enum Added CredentialSet base class and implementations for defining different API credentials Added optional type param to AuthenticationProvider for the specific API credential type to improve type safety Moved AuthenticationProvider/ApiCredentials from BaseApiClient to RestApiClient/SocketApiClient base classes Added optional type params to RestApiClient/SocketApiClient base class to specify the AuthenticationProvider type and credentials type to improve type safety Moved SetOptions/SetApiCredentials from BaseApiClient to RestApiClient/SocketApiClient Extracted LibraryOptions<TRestOptions, TSocketOptions, TEnvironment> without TApiCredentials for libraries without API credentials Removed ApiCredentials from ApiOptions, credentials can only be configured at library, rest or socket level Added EnvironmentName to RestApiClient/SocketApiClient property Added Unknown enum value to Shared interfaces SharedOrderStatus, SharedTransferStatus and SharedTriggerOrderStatus enums Updated Enum converter to map value to an undefined Enum value instead of the first Enum value Added support for checking for missing fields on RestIntegrationTest Added BytesToHexString and HexToBytesString to ExchangeHelpers static class Fixed bug where WebSocket connections are not reconnected when configuring Proxy with SetUpdates Removed legacy CryptoBaseClient, CryptoRestClient and CryptoSocketClient
214 lines
10 KiB
C#
214 lines
10 KiB
C#
using CryptoExchange.Net.Interfaces;
|
|
using CryptoExchange.Net.Objects;
|
|
using Moq;
|
|
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using CryptoExchange.Net.Authentication;
|
|
using System.Collections.Generic;
|
|
using Microsoft.Extensions.Logging;
|
|
using CryptoExchange.Net.Clients;
|
|
using Microsoft.Extensions.Options;
|
|
using System.Linq;
|
|
using CryptoExchange.Net.Converters.SystemTextJson;
|
|
using System.Text.Json.Serialization;
|
|
using System.Net.Http.Headers;
|
|
using CryptoExchange.Net.SharedApis;
|
|
using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters;
|
|
|
|
namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|
{
|
|
public class TestRestClient: BaseRestClient
|
|
{
|
|
public TestRestApi1Client Api1 { get; }
|
|
public TestRestApi2Client Api2 { get; }
|
|
|
|
public TestRestClient(Action<TestClientOptions> optionsDelegate = null)
|
|
: this(null, null, Options.Create(ApplyOptionsDelegate(optionsDelegate)))
|
|
{
|
|
}
|
|
|
|
public TestRestClient(HttpClient httpClient, ILoggerFactory loggerFactory, IOptions<TestClientOptions> options) : base(loggerFactory, "Test")
|
|
{
|
|
Initialize(options.Value);
|
|
|
|
Api1 = new TestRestApi1Client(options.Value);
|
|
Api2 = new TestRestApi2Client(options.Value);
|
|
}
|
|
|
|
public void SetResponse(string responseData, out IRequest requestObj)
|
|
{
|
|
var expectedBytes = Encoding.UTF8.GetBytes(responseData);
|
|
var responseStream = new MemoryStream();
|
|
responseStream.Write(expectedBytes, 0, expectedBytes.Length);
|
|
responseStream.Seek(0, SeekOrigin.Begin);
|
|
|
|
var response = new Mock<IResponse>();
|
|
response.Setup(c => c.IsSuccessStatusCode).Returns(true);
|
|
response.Setup(c => c.GetResponseStreamAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult((Stream)responseStream));
|
|
|
|
var headers = new HttpRequestMessage().Headers;
|
|
var request = new Mock<IRequest>();
|
|
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
|
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));
|
|
request.Setup(c => c.SetContent(It.IsAny<string>(), It.IsAny<Encoding>(), It.IsAny<string>())).Callback(new Action<string, Encoding, string>((content, encoding, type) => { request.Setup(r => r.Content).Returns(content); }));
|
|
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new string[] { val }));
|
|
request.Setup(c => c.GetHeaders()).Returns(() => headers);
|
|
|
|
var factory = Mock.Get(Api1.RequestFactory);
|
|
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
|
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) =>
|
|
{
|
|
request.Setup(a => a.Uri).Returns(uri);
|
|
request.Setup(a => a.Method).Returns(method);
|
|
})
|
|
.Returns(request.Object);
|
|
|
|
factory = Mock.Get(Api2.RequestFactory);
|
|
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
|
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) =>
|
|
{
|
|
request.Setup(a => a.Uri).Returns(uri);
|
|
request.Setup(a => a.Method).Returns(method);
|
|
})
|
|
.Returns(request.Object);
|
|
requestObj = request.Object;
|
|
}
|
|
|
|
public void SetErrorWithoutResponse(HttpStatusCode code, string message)
|
|
{
|
|
var we = new HttpRequestException();
|
|
typeof(HttpRequestException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, message);
|
|
|
|
var request = new Mock<IRequest>();
|
|
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
|
request.Setup(c => c.GetHeaders()).Returns(new HttpRequestMessage().Headers);
|
|
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Throws(we);
|
|
|
|
var factory = Mock.Get(Api1.RequestFactory);
|
|
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
|
.Returns(request.Object);
|
|
|
|
|
|
factory = Mock.Get(Api2.RequestFactory);
|
|
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
|
.Returns(request.Object);
|
|
}
|
|
|
|
public void SetErrorWithResponse(string responseData, HttpStatusCode code)
|
|
{
|
|
var expectedBytes = Encoding.UTF8.GetBytes(responseData);
|
|
var responseStream = new MemoryStream();
|
|
responseStream.Write(expectedBytes, 0, expectedBytes.Length);
|
|
responseStream.Seek(0, SeekOrigin.Begin);
|
|
|
|
var response = new Mock<IResponse>();
|
|
response.Setup(c => c.IsSuccessStatusCode).Returns(false);
|
|
response.Setup(c => c.GetResponseStreamAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult((Stream)responseStream));
|
|
|
|
var headers = new List<KeyValuePair<string, string[]>>();
|
|
var request = new Mock<IRequest>();
|
|
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
|
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));
|
|
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(new KeyValuePair<string, string[]>(key, new string[] { val })));
|
|
request.Setup(c => c.GetHeaders()).Returns(new HttpRequestMessage().Headers);
|
|
|
|
var factory = Mock.Get(Api1.RequestFactory);
|
|
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
|
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
|
.Returns(request.Object);
|
|
|
|
factory = Mock.Get(Api2.RequestFactory);
|
|
factory.Setup(c => c.Create(It.IsAny<Version>(), It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
|
.Callback<Version, HttpMethod, Uri, int>((version, method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
|
.Returns(request.Object);
|
|
}
|
|
}
|
|
|
|
public class TestRestApi1Client : RestApiClient<TestEnvironment, TestAuthProvider, HMACCredential>
|
|
{
|
|
protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler();
|
|
|
|
public TestRestApi1Client(TestClientOptions options) : base(new TraceLogger(), null, "https://localhost:123", options, options.Api1Options)
|
|
{
|
|
RequestFactory = new Mock<IRequestFactory>().Object;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
|
|
|
|
protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions());
|
|
|
|
public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T : class
|
|
{
|
|
return await SendAsync<T>("http://www.test.com", new RequestDefinition("/", HttpMethod.Get) { Weight = 0 }, null, ct);
|
|
}
|
|
|
|
public async Task<CallResult<T>> RequestWithParams<T>(HttpMethod method, ParameterCollection parameters, Dictionary<string, string> headers) where T : class
|
|
{
|
|
return await SendAsync<T>("http://www.test.com", new RequestDefinition("/", method) { Weight = 0 }, parameters, default, additionalHeaders: headers);
|
|
}
|
|
|
|
public void SetParameterPosition(HttpMethod method, HttpMethodParameterPosition position)
|
|
{
|
|
ParameterPositions[method] = position;
|
|
}
|
|
|
|
protected override TestAuthProvider CreateAuthenticationProvider(HMACCredential credentials)
|
|
=> new TestAuthProvider(credentials);
|
|
|
|
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public class TestRestApi2Client : RestApiClient<TestEnvironment, TestAuthProvider, HMACCredential>
|
|
{
|
|
protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler();
|
|
|
|
public TestRestApi2Client(TestClientOptions options) : base(new TraceLogger(), null, "https://localhost:123", options, options.Api2Options)
|
|
{
|
|
RequestFactory = new Mock<IRequestFactory>().Object;
|
|
}
|
|
|
|
protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions());
|
|
|
|
/// <inheritdoc />
|
|
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
|
|
|
|
public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T : class
|
|
{
|
|
return await SendAsync<T>("http://www.test.com", new RequestDefinition("/", HttpMethod.Get) { Weight = 0 }, null, ct);
|
|
}
|
|
|
|
protected override TestAuthProvider CreateAuthenticationProvider(HMACCredential credentials)
|
|
=> new TestAuthProvider(credentials);
|
|
|
|
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
}
|
|
|
|
public class TestError
|
|
{
|
|
[JsonPropertyName("errorCode")]
|
|
public int ErrorCode { get; set; }
|
|
[JsonPropertyName("errorMessage")]
|
|
public string ErrorMessage { get; set; }
|
|
}
|
|
|
|
public class ParseErrorTestRestClient: TestRestClient
|
|
{
|
|
public ParseErrorTestRestClient() { }
|
|
|
|
}
|
|
}
|