Skip to content

Commit

Permalink
Unit testing update (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf authored May 1, 2024
1 parent 96c9a55 commit 050286e
Show file tree
Hide file tree
Showing 25 changed files with 1,736 additions and 217 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,8 @@ public TestAuthProvider(ApiCredentials credentials) : base(credentials)
{
}

public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpMethod method, Dictionary<string, object> providedParameters, bool auth, ArrayParametersSerialization arraySerialization, HttpMethodParameterPosition parameterPosition, RequestBodyFormat bodyFormat, out SortedDictionary<string, object> uriParameters, out SortedDictionary<string, object> bodyParameters, out Dictionary<string, string> headers)
public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpMethod method, IDictionary<string, object> uriParams, IDictionary<string, object> bodyParams, Dictionary<string, string> headers, bool auth, ArrayParametersSerialization arraySerialization, HttpMethodParameterPosition parameterPosition, RequestBodyFormat bodyFormat)
{
bodyParameters = new SortedDictionary<string, object>();
uriParameters = new SortedDictionary<string, object>();
headers = new Dictionary<string, string>();
}

public string GetKey() => _credentials.Key.GetString();
Expand Down
19 changes: 10 additions & 9 deletions CryptoExchange.Net/Authentication/AuthenticationProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.Converters.SystemTextJson;
using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
Expand All @@ -15,6 +16,8 @@ namespace CryptoExchange.Net.Authentication
/// </summary>
public abstract class AuthenticationProvider : IDisposable
{
internal IAuthTimeProvider TimeProvider { get; set; } = new AuthTimeProvider();

/// <summary>
/// Provided credentials
/// </summary>
Expand Down Expand Up @@ -44,7 +47,6 @@ protected AuthenticationProvider(ApiCredentials credentials)
/// <param name="apiClient">The Api client sending the request</param>
/// <param name="uri">The uri for the request</param>
/// <param name="method">The method of the request</param>
/// <param name="providedParameters">The request parameters</param>
/// <param name="auth">If the requests should be authenticated</param>
/// <param name="arraySerialization">Array serialization type</param>
/// <param name="parameterPosition">The position where the providedParameters should go</param>
Expand All @@ -56,14 +58,13 @@ public abstract void AuthenticateRequest(
RestApiClient apiClient,
Uri uri,
HttpMethod method,
Dictionary<string, object> providedParameters,
IDictionary<string, object> uriParameters,
IDictionary<string, object> bodyParameters,
Dictionary<string, string> headers,
bool auth,
ArrayParametersSerialization arraySerialization,
HttpMethodParameterPosition parameterPosition,
RequestBodyFormat requestBodyFormat,
out SortedDictionary<string, object> uriParameters,
out SortedDictionary<string, object> bodyParameters,
out Dictionary<string, string> headers
RequestBodyFormat requestBodyFormat
);

/// <summary>
Expand Down Expand Up @@ -418,17 +419,17 @@ protected static string BytesToBase64String(byte[] buff)
/// </summary>
/// <param name="apiClient"></param>
/// <returns></returns>
protected static DateTime GetTimestamp(RestApiClient apiClient)
protected DateTime GetTimestamp(RestApiClient apiClient)
{
return DateTime.UtcNow.Add(apiClient.GetTimeOffset() ?? TimeSpan.Zero)!;
return TimeProvider.GetTime().Add(apiClient.GetTimeOffset() ?? TimeSpan.Zero)!;
}

/// <summary>
/// Get millisecond timestamp as a string including the time sync offset from the api client
/// </summary>
/// <param name="apiClient"></param>
/// <returns></returns>
protected static string GetMillisecondTimestamp(RestApiClient apiClient)
protected string GetMillisecondTimestamp(RestApiClient apiClient)
{
return DateTimeConverter.ConvertToMilliseconds(GetTimestamp(apiClient)).Value.ToString(CultureInfo.InvariantCulture);
}
Expand Down
74 changes: 41 additions & 33 deletions CryptoExchange.Net/Clients/RestApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,33 @@ public abstract class RestApiClient : BaseApiClient, IRestApiClient
/// <summary>
/// Request body content type
/// </summary>
protected RequestBodyFormat RequestBodyFormat = RequestBodyFormat.Json;
protected internal RequestBodyFormat RequestBodyFormat = RequestBodyFormat.Json;

/// <summary>
/// How to serialize array parameters when making requests
/// </summary>
protected ArrayParametersSerialization ArraySerialization = ArrayParametersSerialization.Array;
protected internal ArrayParametersSerialization ArraySerialization = ArrayParametersSerialization.Array;

/// <summary>
/// What request body should be set when no data is send (only used in combination with postParametersPosition.InBody)
/// </summary>
protected string RequestBodyEmptyContent = "{}";
protected internal string RequestBodyEmptyContent = "{}";

/// <summary>
/// Request headers to be sent with each request
/// </summary>
protected Dictionary<string, string>? StandardRequestHeaders { get; set; }

/// <summary>
/// Whether parameters need to be ordered
/// </summary>
protected internal bool OrderParameters { get; set; } = true;

/// <summary>
/// Parameter order comparer
/// </summary>
protected IComparer<string> ParameterOrderComparer { get; } = new OrderedStringComparer();

/// <summary>
/// Where to put the parameters for requests with different Http methods
/// </summary>
Expand Down Expand Up @@ -269,22 +279,9 @@ protected virtual IRequest CreateRequest(
var bodyFormat = definition.RequestBodyFormat ?? RequestBodyFormat;
var requestId = ExchangeHelpers.NextId();

for (var i = 0; i < parameters.Count; i++)
{
var kvp = parameters.ElementAt(i);
if (kvp.Value is Func<object> delegateValue)
parameters[kvp.Key] = delegateValue();
}

if (parameterPosition == HttpMethodParameterPosition.InUri)
{
foreach (var parameter in parameters)
uri = uri.AddQueryParmeter(parameter.Key, parameter.Value.ToString());
}

var headers = new Dictionary<string, string>();
var uriParameters = parameterPosition == HttpMethodParameterPosition.InUri ? new SortedDictionary<string, object>(parameters) : new SortedDictionary<string, object>();
var bodyParameters = parameterPosition == HttpMethodParameterPosition.InBody ? new SortedDictionary<string, object>(parameters) : new SortedDictionary<string, object>();
var uriParameters = parameterPosition == HttpMethodParameterPosition.InUri ? CreateParameterDictionary(parameters) : new Dictionary<string, object>();
var bodyParameters = parameterPosition == HttpMethodParameterPosition.InBody ? CreateParameterDictionary(parameters) : new Dictionary<string, object>();
if (AuthenticationProvider != null)
{
try
Expand All @@ -293,14 +290,13 @@ protected virtual IRequest CreateRequest(
this,
uri,
definition.Method,
parameters,
uriParameters,
bodyParameters,
headers,
definition.Authenticated,
arraySerialization,
parameterPosition,
bodyFormat,
out uriParameters,
out bodyParameters,
out headers);
bodyFormat);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -346,7 +342,7 @@ protected virtual IRequest CreateRequest(
if (parameterPosition == HttpMethodParameterPosition.InBody)
{
var contentType = bodyFormat == RequestBodyFormat.Json ? Constants.JsonContentHeader : Constants.FormContentHeader;
if (bodyParameters.Any())
if (bodyParameters.Count != 0)
WriteParamBody(request, bodyParameters, contentType);
else
request.SetContent(RequestBodyEmptyContent, contentType);
Expand Down Expand Up @@ -603,7 +599,7 @@ protected virtual async Task<WebCallResult<T>> GetResponseAsync<T>(
if (!valid)
{
// Invalid json
var error = new ServerError("Failed to parse response", accessor.OriginalDataAvailable ? accessor.GetOriginalString() : "[Data only available when OutputOriginal = true in client options]");
var error = new ServerError("Failed to parse response: " + valid.Error!.Message, accessor.OriginalDataAvailable ? accessor.GetOriginalString() : "[Data only available when OutputOriginal = true in client options]");
return new WebCallResult<T>(response.StatusCode, response.ResponseHeaders, sw.Elapsed, responseLength, OutputOriginalData ? accessor.GetOriginalString() : null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, error);
}

Expand Down Expand Up @@ -726,8 +722,8 @@ protected virtual IRequest ConstructRequest(
}

var headers = new Dictionary<string, string>();
var uriParameters = parameterPosition == HttpMethodParameterPosition.InUri ? new SortedDictionary<string, object>(parameters) : new SortedDictionary<string, object>();
var bodyParameters = parameterPosition == HttpMethodParameterPosition.InBody ? new SortedDictionary<string, object>(parameters) : new SortedDictionary<string, object>();
var uriParameters = parameterPosition == HttpMethodParameterPosition.InUri ? CreateParameterDictionary(parameters) : new Dictionary<string, object>();
var bodyParameters = parameterPosition == HttpMethodParameterPosition.InBody ? CreateParameterDictionary(parameters) : new Dictionary<string, object>();
if (AuthenticationProvider != null)
{
try
Expand All @@ -736,14 +732,13 @@ protected virtual IRequest ConstructRequest(
this,
uri,
method,
parameters,
uriParameters,
bodyParameters,
headers,
signed,
arraySerialization,
parameterPosition,
bodyFormat,
out uriParameters,
out bodyParameters,
out headers);
bodyFormat);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -804,7 +799,7 @@ protected virtual IRequest ConstructRequest(
/// <param name="request">The request to set the parameters on</param>
/// <param name="parameters">The parameters to set</param>
/// <param name="contentType">The content type of the data</param>
protected virtual void WriteParamBody(IRequest request, SortedDictionary<string, object> parameters, string contentType)
protected virtual void WriteParamBody(IRequest request, IDictionary<string, object> parameters, string contentType)
{
if (contentType == Constants.JsonContentHeader)
{
Expand Down Expand Up @@ -859,6 +854,19 @@ protected virtual ServerRateLimitError ParseRateLimitResponse(int httpStatusCode
return new ServerRateLimitError(message);
}

/// <summary>
/// Create the parameter IDictionary
/// </summary>
/// <param name="parameters"></param>
/// <returns></returns>
protected internal IDictionary<string, object> CreateParameterDictionary(IDictionary<string, object> parameters)
{
if (!OrderParameters)
return parameters;

return new SortedDictionary<string, object>(parameters, ParameterOrderComparer);
}

/// <summary>
/// Retrieve the server time for the purpose of syncing time between client and server to prevent authentication issues
/// </summary>
Expand Down
Loading

0 comments on commit 050286e

Please sign in to comment.