Skip to content

Commit a6d6ecd

Browse files
authored
test(csharp): add client CTS (#2551)
1 parent 3316753 commit a6d6ecd

File tree

13 files changed

+141
-41
lines changed

13 files changed

+141
-41
lines changed

clients/algoliasearch-client-csharp/algoliasearch/Clients/AlgoliaConfig.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,25 @@ public abstract class AlgoliaConfig
1616
private static readonly string ClientVersion =
1717
typeof(AlgoliaConfig).GetTypeInfo().Assembly.GetName().Version.ToString();
1818

19+
// get the dotnet runtime version
20+
private static readonly string DotnetVersion = Environment.Version.ToString();
21+
1922
/// <summary>
2023
/// Create a new Algolia's configuration for the given credentials
2124
/// </summary>
22-
/// <param name="applicationId">Your application ID</param>
25+
/// <param name="appId">Your application ID</param>
2326
/// <param name="apiKey">Your API Key</param>
24-
protected AlgoliaConfig(string applicationId, string apiKey)
27+
/// <param name="client">The client name</param>
28+
protected AlgoliaConfig(string appId, string apiKey, string client)
2529
{
26-
AppId = applicationId;
30+
AppId = appId;
2731
ApiKey = apiKey;
2832

2933
DefaultHeaders = new Dictionary<string, string>
3034
{
3135
{ Defaults.AlgoliaApplicationHeader.ToLowerInvariant(), AppId },
3236
{ Defaults.AlgoliaApiKeyHeader.ToLowerInvariant(), ApiKey },
33-
{ Defaults.UserAgentHeader.ToLowerInvariant(), $"Algolia For Csharp {ClientVersion}" },
37+
{ Defaults.UserAgentHeader.ToLowerInvariant(), $"Algolia for Csharp ({ClientVersion}); {client} ({ClientVersion}); Dotnet ({DotnetVersion})" },
3438
{ Defaults.Connection.ToLowerInvariant(), Defaults.KeepAlive },
3539
{ Defaults.AcceptHeader.ToLowerInvariant(), JsonConfig.JsonContentType }
3640
};
@@ -69,6 +73,11 @@ protected AlgoliaConfig(string applicationId, string apiKey)
6973
/// </summary>
7074
public TimeSpan? WriteTimeout { get; set; }
7175

76+
/// <summary>
77+
/// Set the connect timeout for all requests
78+
/// </summary>
79+
public TimeSpan? ConnectTimeout { get; set; }
80+
7281
/// <summary>
7382
/// Compression for outgoing http requests <see cref="CompressionType"/>
7483
/// </summary>

clients/algoliasearch-client-csharp/algoliasearch/Http/AlgoliaHttpRequester.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ internal class AlgoliaHttpRequester : IHttpRequester
2727
/// Send request to the REST API
2828
/// </summary>
2929
/// <param name="request">Request</param>
30-
/// <param name="totalTimeout">Timeout</param>
30+
/// <param name="requestTimeout">Request timeout</param>
31+
/// <param name="connectTimeout">Connect timeout</param>
3132
/// <param name="ct">Optional cancellation token</param>
3233
/// <returns></returns>
33-
public async Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpan totalTimeout,
34-
CancellationToken ct = default)
34+
public async Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpan requestTimeout, TimeSpan connectTimeout,
35+
CancellationToken ct = default)
3536
{
3637
if (request.Method == null)
3738
{
@@ -57,7 +58,7 @@ public async Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpa
5758
}
5859

5960
httpRequestMessage.Headers.Fill(request.Headers);
60-
httpRequestMessage.SetTimeout(totalTimeout);
61+
httpRequestMessage.SetTimeout(requestTimeout + connectTimeout);
6162

6263
try
6364
{

clients/algoliasearch-client-csharp/algoliasearch/Http/EchoHttpRequester.cs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,21 @@ private static Dictionary<string, string> SplitQuery(string query)
2121
return collection.AllKeys.ToDictionary(key => key, key => collection[key]);
2222
}
2323

24-
public async Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpan totalTimeout,
24+
public async Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpan requestTimeout,
25+
TimeSpan connectTimeout,
2526
CancellationToken ct = default)
2627
{
27-
EchoResponse echo = new EchoResponse();
28-
echo.Path = request.Uri.AbsolutePath;
29-
echo.Host = request.Uri.Host;
30-
echo.Method = request.Method;
31-
echo.Body = request.Body;
32-
echo.QueryParameters = SplitQuery(request.Uri.Query);
33-
echo.Headers = new Dictionary<string, string>(request.Headers);
28+
EchoResponse echo = new EchoResponse
29+
{
30+
Path = request.Uri.AbsolutePath,
31+
Host = request.Uri.Host,
32+
Method = request.Method,
33+
Body = request.Body,
34+
QueryParameters = SplitQuery(request.Uri.Query),
35+
Headers = new Dictionary<string, string>(request.Headers),
36+
ConnectTimeout = connectTimeout,
37+
ResponseTimeout = requestTimeout
38+
};
3439

3540
LastResponse = echo;
3641

clients/algoliasearch-client-csharp/algoliasearch/Http/EchoResponse.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class EchoResponse
1313
public String Body;
1414
public Dictionary<string, string> QueryParameters;
1515
public Dictionary<string, string> Headers;
16-
public int ConnectTimeout;
17-
public int ResponseTimeout;
16+
public TimeSpan ConnectTimeout;
17+
public TimeSpan ResponseTimeout;
1818
}
1919
}

clients/algoliasearch-client-csharp/algoliasearch/Http/IHttpRequester.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ public interface IHttpRequester
1414
/// Sends the HTTP request
1515
/// </summary>
1616
/// <param name="request">Request object</param>
17-
/// <param name="totalTimeout">Timeout</param>
17+
/// <param name="requestTimeout">Request timeout</param>
18+
/// <param name="connectTimeout">Connect timeout</param>
1819
/// <param name="ct">Optional cancellation token</param>
1920
/// <returns></returns>
20-
Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpan totalTimeout,
21-
CancellationToken ct = default);
21+
Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpan requestTimeout, TimeSpan connectTimeout, CancellationToken ct = default);
2222
}
2323
}

clients/algoliasearch-client-csharp/algoliasearch/Transport/HttpTransport.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ private async Task<TResult> ExecuteRequestAsync<TResult, TData>(HttpMethod metho
121121
}
122122

123123
AlgoliaHttpResponse response = await _httpClient
124-
.SendRequestAsync(request, requestTimeout, ct)
124+
.SendRequestAsync(request, requestTimeout, _algoliaConfig.ConnectTimeout ?? Defaults.ConnectTimeout, ct)
125125
.ConfigureAwait(false);
126126

127127
_errorMessage = response.Error;

clients/algoliasearch-client-csharp/algoliasearch/Utils/Defaults.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ internal class Defaults
1717
/// </summary>
1818
public static TimeSpan WriteTimeout = TimeSpan.FromSeconds(30);
1919

20+
/// <summary>
21+
/// Connect timeout
22+
/// </summary>
23+
public static TimeSpan ConnectTimeout = TimeSpan.FromSeconds(2);
24+
2025
public const string AcceptHeader = "Accept";
2126
public const string AlgoliaApplicationHeader = "X-Algolia-Application-Id";
2227
public const string AlgoliaApiKeyHeader = "X-Algolia-API-Key";

templates/csharp/Configuration.mustache

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ namespace Algolia.Search.Clients
1818
/// The configuration of the {{packageName}} client
1919
/// A client should have it's own configuration ie on configuration per client instance
2020
/// </summary>
21-
/// <param name="applicationId">Your application ID</param>
21+
/// <param name="appId">Your application ID</param>
2222
/// <param name="apiKey">Your API Key</param>
2323
/// <param name="region">Targeted region {{#fallbackToAliasHost}}(optional){{/fallbackToAliasHost}}</param>
24-
public {{packageName}}Config(string applicationId, string apiKey, string region{{#fallbackToAliasHost}} = null{{/fallbackToAliasHost}}) : base(applicationId, apiKey)
24+
public {{packageName}}Config(string appId, string apiKey, string region{{#fallbackToAliasHost}} = null{{/fallbackToAliasHost}}) : base(appId, apiKey, "{{packageName}}")
2525
{
2626
DefaultHosts = GetDefaultHosts(region);
2727
Compression = CompressionType.NONE;
@@ -32,51 +32,51 @@ namespace Algolia.Search.Clients
3232
/// The configuration of the {{packageName}} client
3333
/// A client should have it's own configuration ie on configuration per client instance
3434
/// </summary>
35-
/// <param name="applicationId">Your application ID</param>
35+
/// <param name="appId">Your application ID</param>
3636
/// <param name="apiKey">Your API Key</param>
37-
public {{packageName}}Config(string applicationId, string apiKey) : base(applicationId, apiKey)
37+
public {{packageName}}Config(string appId, string apiKey) : base(appId, apiKey, "{{packageName}}")
3838
{
39-
DefaultHosts = GetDefaultHosts(applicationId);
39+
DefaultHosts = GetDefaultHosts(appId);
4040
Compression = CompressionType.NONE;
4141
}
4242
{{/hasRegionalHost}}
4343
{{^hasRegionalHost}}
44-
private static List<StatefulHost> GetDefaultHosts(string applicationId)
44+
private static List<StatefulHost> GetDefaultHosts(string appId)
4545
{
4646
List<StatefulHost> hosts = new List<StatefulHost>
4747
{
4848
new StatefulHost
4949
{
50-
Url = $"{applicationId}-dsn.algolia.net",
50+
Url = $"{appId}-dsn.algolia.net",
5151
Up = true,
5252
LastUse = DateTime.UtcNow,
5353
Accept = CallType.Read
5454
},
5555
new StatefulHost
5656
{
57-
Url = $"{applicationId}.algolia.net", Up = true, LastUse = DateTime.UtcNow, Accept = CallType.Write,
57+
Url = $"{appId}.algolia.net", Up = true, LastUse = DateTime.UtcNow, Accept = CallType.Write,
5858
}
5959
};
6060

6161
var commonHosts = new List<StatefulHost>
6262
{
6363
new StatefulHost
6464
{
65-
Url = $"{applicationId}-1.algolianet.com",
65+
Url = $"{appId}-1.algolianet.com",
6666
Up = true,
6767
LastUse = DateTime.UtcNow,
6868
Accept = CallType.Read | CallType.Write,
6969
},
7070
new StatefulHost
7171
{
72-
Url = $"{applicationId}-2.algolianet.com",
72+
Url = $"{appId}-2.algolianet.com",
7373
Up = true,
7474
LastUse = DateTime.UtcNow,
7575
Accept = CallType.Read | CallType.Write,
7676
},
7777
new StatefulHost
7878
{
79-
Url = $"{applicationId}-3.algolianet.com",
79+
Url = $"{appId}-3.algolianet.com",
8080
Up = true,
8181
LastUse = DateTime.UtcNow,
8282
Accept = CallType.Read | CallType.Write,
@@ -91,10 +91,18 @@ namespace Algolia.Search.Clients
9191
private static List<StatefulHost> GetDefaultHosts(string region)
9292
{
9393
var regions = new List<string> { {{#allowedRegions}}"{{.}}"{{^-last}},{{/-last}}{{/allowedRegions}} };
94-
if (region != null && !regions.Contains(region))
94+
{{^fallbackToAliasHost}}
95+
if (region == null || !regions.Contains(region))
9596
{
96-
throw new ArgumentException($"`region` must be one of the following {regions}");
97+
throw new ArgumentException($"`region` is required and must be one of the following: {string.Join(", ", regions)}");
9798
}
99+
{{/fallbackToAliasHost}}
100+
{{#fallbackToAliasHost}}
101+
if(region != null && !regions.Contains(region))
102+
{
103+
throw new ArgumentException($"`region` must be one of the following: {string.Join(", ", regions)}");
104+
}
105+
{{/fallbackToAliasHost}}
98106

99107
var selectedRegion = {{#fallbackToAliasHost}}region == null ? "{{{hostWithFallback}}}" : {{/fallbackToAliasHost}} "{{{regionalHost}}}".Replace("{region}", region);
100108

templates/csharp/libraries/httpclient/api.mustache

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,19 @@ namespace Algolia.Search.Clients
7979
{
8080
if (httpRequester == null)
8181
{
82-
throw new ArgumentNullException(nameof(httpRequester), "An httpRequester is required");
82+
throw new ArgumentException("An httpRequester is required");
8383
}
8484
if (config == null)
8585
{
86-
throw new ArgumentNullException(nameof(config), "A config is required");
86+
throw new ArgumentException("A config is required");
8787
}
8888
if (string.IsNullOrWhiteSpace(config.AppId))
8989
{
90-
throw new ArgumentNullException(nameof(config.AppId), "Application ID is required");
90+
throw new ArgumentException("`AppId` is missing.");
9191
}
9292
if (string.IsNullOrWhiteSpace(config.ApiKey))
9393
{
94-
throw new ArgumentNullException(nameof(config.ApiKey), "An API key is required");
94+
throw new ArgumentException("`ApiKey` is missing.");
9595
}
9696

9797
_config = config;
@@ -120,8 +120,7 @@ namespace Algolia.Search.Clients
120120
{{#required}}
121121
{{^vendorExtensions.x-csharp-value-type}}
122122
if ({{paramName}} == null)
123-
throw new ApiException(400, "Missing required parameter '{{paramName}}' when calling {{classname}}->{{operationId}}");
124-
123+
throw new ApiException(400, "Parameter `{{paramName}}` is required when calling `{{operationId}}`.");
125124
{{/vendorExtensions.x-csharp-value-type}}
126125
{{/required}}
127126
{{/allParams}}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{^autoCreateClient}}var client = {{/autoCreateClient}}new {{client}}(new {{clientPrefix}}Config("{{parametersWithDataTypeMap.appId.value}}","{{parametersWithDataTypeMap.apiKey.value}}"{{#hasRegionalHost}}{{#parametersWithDataTypeMap.region}},"{{parametersWithDataTypeMap.region.value}}"{{/parametersWithDataTypeMap.region}}{{/hasRegionalHost}}), _echo);

0 commit comments

Comments
 (0)