Skip to content

Commit 4687fc2

Browse files
authored
Make ElasticsearchClient more mockable. (#6951)
1 parent f878759 commit 4687fc2

19 files changed

+851
-736
lines changed

Directory.Build.targets

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
</PropertyGroup>
77
<PropertyGroup Condition="$(IsPackable) == True">
88
<OutDir>bin/$(Configuration)/$(TargetFramework)/</OutDir>
9-
<NoWarn>1591,1572,1571,1573,1587,1570,NU5048,</NoWarn>
9+
<NoWarn>1591,1572,1571,1573,1587,1570,NU5048</NoWarn>
10+
<CheckEolTargetFramework>false</CheckEolTargetFramework>
1011
<Prefer32Bit>false</Prefer32Bit>
1112
<DebugSymbols>true</DebugSymbols>
1213

src/Elastic.Clients.Elasticsearch/Client/ElasticsearchClient-BulkAll.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ namespace Elastic.Clients.Elasticsearch;
1010

1111
public partial class ElasticsearchClient
1212
{
13-
public BulkAllObservable<T> BulkAll<T>(IEnumerable<T> documents, Action<BulkAllRequestDescriptor<T>> configure, CancellationToken cancellationToken = default)
13+
public virtual BulkAllObservable<T> BulkAll<T>(IEnumerable<T> documents, Action<BulkAllRequestDescriptor<T>> configure, CancellationToken cancellationToken = default)
1414
{
1515
var descriptor = new BulkAllRequestDescriptor<T>(documents);
1616
configure?.Invoke(descriptor);
1717
return BulkAll<T>(descriptor, cancellationToken);
1818
}
1919

20-
public BulkAllObservable<T> BulkAll<T>(IBulkAllRequest<T> request, CancellationToken cancellationToken = default) =>
20+
public virtual BulkAllObservable<T> BulkAll<T>(IBulkAllRequest<T> request, CancellationToken cancellationToken = default) =>
2121
new(this, request, cancellationToken);
2222
}

src/Elastic.Clients.Elasticsearch/Client/ElasticsearchClient-Manual.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,26 @@ namespace Elastic.Clients.Elasticsearch;
1010

1111
public partial class ElasticsearchClient
1212
{
13-
public Task<UpdateResponse<TDocument>> UpdateAsync<TDocument, TPartialDocument>(IndexName index, Id id, CancellationToken cancellationToken = default)
13+
public virtual Task<UpdateResponse<TDocument>> UpdateAsync<TDocument, TPartialDocument>(IndexName index, Id id, CancellationToken cancellationToken = default)
1414
{
1515
var descriptor = new UpdateRequestDescriptor<TDocument, TPartialDocument>(index, id);
16-
return DoRequestAsync<UpdateRequestDescriptor<TDocument, TPartialDocument>, UpdateResponse<TDocument>, UpdateRequestParameters>(descriptor);
16+
return DoRequestAsync<UpdateRequestDescriptor<TDocument, TPartialDocument>, UpdateResponse<TDocument>, UpdateRequestParameters>(descriptor, cancellationToken);
1717
}
1818

19-
public Task<UpdateResponse<TDocument>> UpdateAsync<TDocument, TPartialDocument>(IndexName index, Id id, Action<UpdateRequestDescriptor<TDocument, TPartialDocument>> configureRequest, CancellationToken cancellationToken = default)
19+
public virtual Task<UpdateResponse<TDocument>> UpdateAsync<TDocument, TPartialDocument>(IndexName index, Id id, Action<UpdateRequestDescriptor<TDocument, TPartialDocument>> configureRequest, CancellationToken cancellationToken = default)
2020
{
2121
var descriptor = new UpdateRequestDescriptor<TDocument, TPartialDocument>(index, id);
2222
configureRequest?.Invoke(descriptor);
23-
return DoRequestAsync<UpdateRequestDescriptor<TDocument, TPartialDocument>, UpdateResponse<TDocument>, UpdateRequestParameters>(descriptor);
23+
return DoRequestAsync<UpdateRequestDescriptor<TDocument, TPartialDocument>, UpdateResponse<TDocument>, UpdateRequestParameters>(descriptor, cancellationToken);
2424
}
2525

26-
public UpdateResponse<TDocument> Update<TDocument, TPartialDocument>(IndexName index, Id id)
26+
public virtual UpdateResponse<TDocument> Update<TDocument, TPartialDocument>(IndexName index, Id id)
2727
{
2828
var descriptor = new UpdateRequestDescriptor<TDocument, TPartialDocument>(index, id);
2929
return DoRequest<UpdateRequestDescriptor<TDocument, TPartialDocument>, UpdateResponse<TDocument>, UpdateRequestParameters>(descriptor);
3030
}
3131

32-
public UpdateResponse<TDocument> Update<TDocument, TPartialDocument>(IndexName index, Id id, Action<UpdateRequestDescriptor<TDocument, TPartialDocument>> configureRequest)
32+
public virtual UpdateResponse<TDocument> Update<TDocument, TPartialDocument>(IndexName index, Id id, Action<UpdateRequestDescriptor<TDocument, TPartialDocument>> configureRequest)
3333
{
3434
var descriptor = new UpdateRequestDescriptor<TDocument, TPartialDocument>(index, id);
3535
configureRequest?.Invoke(descriptor);

src/Elastic.Clients.Elasticsearch/Client/ElasticsearchClient.cs

+15-20
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,39 @@
88
using System.Text.Json;
99
using System.Threading;
1010
using System.Threading.Tasks;
11-
using Elastic.Clients.Elasticsearch.IndexManagement;
1211
using Elastic.Clients.Elasticsearch.Requests;
1312
using Elastic.Transport;
1413
using Elastic.Transport.Products.Elasticsearch;
1514

1615
namespace Elastic.Clients.Elasticsearch;
1716

18-
/// <inheritdoc />
19-
public sealed partial class ElasticsearchClient
17+
/// <summary>
18+
/// A strongly-typed client for communicating with Elasticsearch server endpoints.
19+
/// </summary>
20+
public partial class ElasticsearchClient
2021
{
2122
private readonly HttpTransport<IElasticsearchClientSettings> _transport;
2223

2324
internal static ConditionalWeakTable<JsonSerializerOptions, IElasticsearchClientSettings> SettingsTable { get; } = new();
2425

2526
/// <summary>
26-
/// Creates a client configured to connect to localhost:9200.
27+
/// Creates a client configured to connect to http://localhost:9200.
2728
/// </summary>
2829
public ElasticsearchClient() : this(new ElasticsearchClientSettings(new Uri("http://localhost:9200"))) { }
2930

3031
/// <summary>
31-
/// Creates a client configured to connect to a node reachable at the provided <paramref name="uri" />.
32+
/// Creates a client configured to connect to a node reachable at the provided <paramref name="uri" />.
3233
/// </summary>
3334
/// <param name="uri">The <see cref="Uri" /> to connect to.</param>
3435
public ElasticsearchClient(Uri uri) : this(new ElasticsearchClientSettings(uri)) { }
3536

3637
/// <summary>
37-
/// Creates a client configured to communicate with Elastic Cloud using the provided <paramref name="cloudId" />.
38-
/// <para>See the <see cref="CloudNodePool" /> documentation for more information on how to obtain your Cloud Id.</para>
39-
/// <para>
40-
/// If you want more control, use the <see cref="ElasticsearchClient(IElasticsearchClientSettings)" /> constructor and
41-
/// pass
42-
/// an instance of
43-
/// <see cref="ElasticsearchClientSettings" /> that takes a <paramref name="cloudId" /> in its constructor as well.
44-
/// </para>
38+
/// Creates a client configured to communicate with Elastic Cloud using the provided <paramref name="cloudId" />.
39+
/// <para>See the <see cref="CloudNodePool" /> documentation for more information on how to obtain your Cloud Id.</para>
40+
/// <para>
41+
/// If you want more control, use the <see cref="ElasticsearchClient(IElasticsearchClientSettings)" /> constructor and
42+
/// pass an instance of <see cref="ElasticsearchClientSettings" /> that takes a <paramref name="cloudId" /> in its constructor as well.
43+
/// </para>
4544
/// </summary>
4645
/// <param name="cloudId">The Cloud ID of an Elastic Cloud deployment.</param>
4746
/// <param name="credentials">The credentials to use for the connection.</param>
@@ -51,19 +50,15 @@ public ElasticsearchClient(string cloudId, AuthorizationHeader credentials) : th
5150
}
5251

5352
/// <summary>
54-
/// TODO
53+
/// Creates a client using the provided configuration to initialise the client.
5554
/// </summary>
56-
/// <param name="elasticsearchClientSettings"></param>
55+
/// <param name="elasticsearchClientSettings">The <see cref="IElasticsearchClientSettings"/> used to configure the client.</param>
5756
public ElasticsearchClient(IElasticsearchClientSettings elasticsearchClientSettings)
5857
: this(new DefaultHttpTransport<IElasticsearchClientSettings>(elasticsearchClientSettings))
5958
{
6059
}
6160

62-
/// <summary>
63-
/// TODO
64-
/// </summary>
65-
/// <param name="transport"></param>
66-
public ElasticsearchClient(HttpTransport<IElasticsearchClientSettings> transport)
61+
internal ElasticsearchClient(HttpTransport<IElasticsearchClientSettings> transport)
6762
{
6863
transport.ThrowIfNull(nameof(transport));
6964
transport.Settings.ThrowIfNull(nameof(transport.Settings));

src/Elastic.Clients.Elasticsearch/Client/IndicesNamespace.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Elastic.Clients.Elasticsearch.IndexManagement;
99

10-
public partial class IndicesNamespace
10+
public partial class IndicesNamespacedClient
1111
{
1212
/// <summary>
1313
/// Refresh one or more indices. A refresh makes recent operations performed on one or more indices available for search. For data streams,

src/Elastic.Clients.Elasticsearch/Client/NamespacedClientProxy.cs

+44-16
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111

1212
namespace Elastic.Clients.Elasticsearch;
1313

14-
/// <summary>
15-
/// </summary>
16-
/// <remarks>
17-
/// Not intended to be used directly.
18-
/// </remarks>
1914
public abstract class NamespacedClientProxy
2015
{
16+
private const string InvalidOperation = "The client has not been initialised for proper usage as may have been partially mocked. Ensure you are using a " +
17+
"new instance of ElasticsearchClient to perform requests over a network to Elasticsearch.";
18+
2119
private readonly ElasticsearchClient _client;
20+
21+
/// <summary>
22+
/// Initializes a new instance for mocking.
23+
/// </summary>
24+
protected NamespacedClientProxy() { }
2225

2326
internal NamespacedClientProxy(ElasticsearchClient client) => _client = client;
2427

@@ -28,33 +31,53 @@ internal TResponse DoRequest<TRequest, TResponse, TRequestParameters>(
2831
Action<IRequestConfiguration>? forceConfiguration = null)
2932
where TRequest : Request<TRequestParameters>
3033
where TResponse : ElasticsearchResponse, new()
31-
where TRequestParameters : RequestParameters, new() =>
32-
_client.DoRequest<TRequest, TResponse, TRequestParameters>(request, parameters, forceConfiguration);
34+
where TRequestParameters : RequestParameters, new()
35+
{
36+
if (_client is null)
37+
ThrowHelper.ThrowInvalidOperationException(InvalidOperation);
38+
39+
return _client.DoRequest<TRequest, TResponse, TRequestParameters>(request, parameters, forceConfiguration);
40+
}
3341

3442
internal TResponse DoRequest<TRequest, TResponse, TRequestParameters>(
3543
TRequest request,
3644
Action<IRequestConfiguration>? forceConfiguration = null)
3745
where TRequest : Request<TRequestParameters>
3846
where TResponse : ElasticsearchResponse, new()
39-
where TRequestParameters : RequestParameters, new() =>
40-
_client.DoRequest<TRequest, TResponse, TRequestParameters>(request, forceConfiguration);
47+
where TRequestParameters : RequestParameters, new()
48+
{
49+
if (_client is null)
50+
ThrowHelper.ThrowInvalidOperationException(InvalidOperation);
51+
52+
return _client.DoRequest<TRequest, TResponse, TRequestParameters>(request, forceConfiguration);
53+
}
4154

4255
internal Task<TResponse> DoRequestAsync<TRequest, TResponse, TRequestParameters>(
4356
TRequest request,
44-
TRequestParameters parameters,
4557
CancellationToken cancellationToken = default)
4658
where TRequest : Request<TRequestParameters>
4759
where TResponse : ElasticsearchResponse, new()
48-
where TRequestParameters : RequestParameters, new() =>
49-
_client.DoRequestAsync<TRequest, TResponse, TRequestParameters>(request, parameters, cancellationToken: cancellationToken);
60+
where TRequestParameters : RequestParameters, new()
61+
{
62+
if (_client is null)
63+
ThrowHelper.ThrowInvalidOperationException(InvalidOperation);
64+
65+
return _client.DoRequestAsync<TRequest, TResponse, TRequestParameters>(request, cancellationToken: cancellationToken);
66+
}
5067

5168
internal Task<TResponse> DoRequestAsync<TRequest, TResponse, TRequestParameters>(
5269
TRequest request,
70+
TRequestParameters parameters,
5371
CancellationToken cancellationToken = default)
5472
where TRequest : Request<TRequestParameters>
5573
where TResponse : ElasticsearchResponse, new()
56-
where TRequestParameters : RequestParameters, new() =>
57-
_client.DoRequestAsync<TRequest, TResponse, TRequestParameters>(request, cancellationToken: cancellationToken);
74+
where TRequestParameters : RequestParameters, new()
75+
{
76+
if (_client is null)
77+
ThrowHelper.ThrowInvalidOperationException(InvalidOperation);
78+
79+
return _client.DoRequestAsync<TRequest, TResponse, TRequestParameters>(request, parameters, cancellationToken: cancellationToken);
80+
}
5881

5982
internal Task<TResponse> DoRequestAsync<TRequest, TResponse, TRequestParameters>(
6083
TRequest request,
@@ -63,6 +86,11 @@ internal Task<TResponse> DoRequestAsync<TRequest, TResponse, TRequestParameters>
6386
CancellationToken cancellationToken = default)
6487
where TRequest : Request<TRequestParameters>
6588
where TResponse : ElasticsearchResponse, new()
66-
where TRequestParameters : RequestParameters, new() =>
67-
_client.DoRequestAsync<TRequest, TResponse, TRequestParameters>(request, parameters, forceConfiguration, cancellationToken);
89+
where TRequestParameters : RequestParameters, new()
90+
{
91+
if (_client is null)
92+
ThrowHelper.ThrowInvalidOperationException(InvalidOperation);
93+
94+
return _client.DoRequestAsync<TRequest, TResponse, TRequestParameters>(request, parameters, forceConfiguration, cancellationToken);
95+
}
6896
}

src/Elastic.Clients.Elasticsearch/Core/Exceptions/ThrowHelper.cs

+6
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,11 @@ internal static void ThrowUnknownTaggedUnionVariantJsonException(string variantT
1818
throw new JsonException($"Encounted an unsupported variant tag '{variantTag}' on '{SimplifiedFullName(interfaceType)}', which could not be deserialised.");
1919

2020
[MethodImpl(MethodImplOptions.NoInlining)]
21+
internal static void ThrowInvalidOperationException(string message) =>
22+
throw new InvalidOperationException(message);
23+
24+
[MethodImpl(MethodImplOptions.NoInlining)]
25+
#pragma warning disable IDE0057 // Use range operator
2126
private static string SimplifiedFullName(Type type) => type.FullName.Substring(30);
27+
#pragma warning restore IDE0057 // Use range operator
2228
}

0 commit comments

Comments
 (0)